1use std::num::NonZeroU32;
4
5use parking_lot::Mutex;
6use unic_langid::LanguageIdentifier;
7use zng_layout::unit::{Factor, PxSize, PxTransform};
8use zng_state_map::{StateId, static_id};
9use zng_txt::Txt;
10use zng_unique_id::IdMap;
11use zng_var::{IntoVar, Var};
12pub use zng_view_api::access::{
13 AccessCmdName, AccessRole, AutoComplete, CurrentKind, Invalid, LiveIndicator, Orientation, Popup, SortDirection,
14};
15use zng_view_api::access::{AccessNodeId, AccessState};
16
17use crate::widget::WidgetId;
18
19use super::{WidgetInfo, WidgetInfoBuilder, WidgetInfoTree, iter::TreeIterator};
20
21impl WidgetInfoBuilder {
22 pub fn access(&mut self) -> Option<WidgetAccessInfoBuilder<'_>> {
26 if self.access_enabled.is_enabled() {
27 Some(WidgetAccessInfoBuilder { builder: self })
28 } else {
29 None
30 }
31 }
32}
33
34pub struct WidgetAccessInfoBuilder<'a> {
36 pub(super) builder: &'a mut WidgetInfoBuilder,
37}
38impl WidgetAccessInfoBuilder<'_> {
39 fn with_access(&mut self, f: impl FnOnce(&mut AccessInfo)) {
40 self.builder.with_meta(move |mut m| f(m.entry(*ACCESS_INFO_ID).or_default()))
41 }
42
43 pub fn set_role(&mut self, role: AccessRole) {
45 self.with_access(|a| a.role = Some(role))
46 }
47
48 pub fn push_command(&mut self, cmd: AccessCmdName) {
50 self.with_access(|a| a.commands.push(cmd))
51 }
52
53 pub fn set_auto_complete(&mut self, mode: AutoComplete) {
60 self.with_access(|a| a.set_state(AccessState::AutoComplete(mode)))
61 }
62
63 pub fn set_checked(&mut self, checked: Option<bool>) {
65 self.with_access(|a| a.set_state(AccessState::Checked(checked)))
66 }
67
68 pub fn set_current(&mut self, kind: CurrentKind) {
70 self.with_access(|a| a.set_state(AccessState::Current(kind)))
71 }
72
73 pub fn set_error_message(&mut self, invalid_wgt: impl Into<WidgetId>) {
79 let invalid_wgt = invalid_wgt.into();
80 self.with_access(|a| a.set_state(AccessState::ErrorMessage(invalid_wgt.into())))
81 }
82
83 pub fn set_active_descendant(&mut self, descendant: impl Into<WidgetId>) {
85 let descendant = descendant.into();
86 self.with_access(|a| a.set_state(AccessState::ActiveDescendant(descendant.into())))
87 }
88
89 pub fn set_expanded(&mut self, expanded: bool) {
97 self.with_access(|a| a.set_state(AccessState::Expanded(expanded)))
98 }
99
100 pub fn set_popup(&mut self, popup: Popup) {
102 self.with_access(|a| a.set_state(AccessState::Popup(popup)))
103 }
104
105 pub fn set_invalid(&mut self, error: Invalid) {
107 self.with_access(|a| a.set_state(AccessState::Invalid(error)));
108 }
109
110 pub fn set_label(&mut self, name: impl Into<Txt>) {
114 let name = name.into();
115 self.with_access(|a| a.set_state_source(AccessStateSource::Label(name)))
116 }
117
118 pub fn set_level(&mut self, hierarchical_level: NonZeroU32) {
120 self.with_access(|a| a.set_state(AccessState::Level(hierarchical_level)))
121 }
122
123 pub fn flag_multi_selectable(&mut self) {
125 self.with_access(|a| a.set_state(AccessState::MultiSelectable))
126 }
127
128 pub fn set_orientation(&mut self, orientation: Orientation) {
130 self.with_access(|a| a.set_state(AccessState::Orientation(orientation)))
131 }
132
133 pub fn set_placeholder(&mut self, placeholder: impl Into<Txt>) {
135 let placeholder = placeholder.into();
136 self.with_access(|a| a.set_state_source(AccessStateSource::Placeholder(placeholder)))
137 }
138
139 pub fn flag_read_only(&mut self) {
141 self.with_access(|a| a.set_state(AccessState::ReadOnly))
142 }
143
144 pub fn flag_required(&mut self) {
146 self.with_access(|a| a.set_state(AccessState::Required))
147 }
148
149 pub fn flag_selected(&mut self) {
151 self.with_access(|a| a.set_state(AccessState::Selected))
152 }
153
154 pub fn set_sort(&mut self, direction: SortDirection) {
156 self.with_access(|a| a.set_state(AccessState::Sort(direction)))
157 }
158
159 pub fn set_value_max(&mut self, max: f64) {
161 self.with_access(|a| a.set_state(AccessState::ValueMax(max)))
162 }
163
164 pub fn set_value_min(&mut self, min: f64) {
166 self.with_access(|a| a.set_state(AccessState::ValueMin(min)))
167 }
168
169 pub fn set_value(&mut self, value: f64) {
171 self.with_access(|a| a.set_state(AccessState::Value(value)))
172 }
173
174 pub fn set_value_text(&mut self, value: impl Into<Txt>) {
176 let value = value.into();
177 self.with_access(|a| a.set_state_source(AccessStateSource::ValueText(value)))
178 }
179
180 pub fn set_live(&mut self, indicator: LiveIndicator, atomic: bool, busy: bool) {
183 self.with_access(|a| a.set_state(AccessState::Live { indicator, atomic, busy }))
184 }
185
186 pub fn set_col_count(&mut self, count: usize) {
194 self.with_access(|a| a.set_state(AccessState::ColCount(count)))
195 }
196
197 pub fn set_col_index(&mut self, index: usize) {
199 self.with_access(|a| a.set_state(AccessState::ColIndex(index)))
200 }
201
202 pub fn set_col_span(&mut self, span: usize) {
204 self.with_access(|a| a.set_state(AccessState::ColSpan(span)))
205 }
206
207 pub fn set_row_count(&mut self, count: usize) {
215 self.with_access(|a| a.set_state(AccessState::RowCount(count)))
216 }
217
218 pub fn set_row_index(&mut self, index: usize) {
220 self.with_access(|a| a.set_state(AccessState::RowIndex(index)))
221 }
222
223 pub fn set_row_span(&mut self, span: usize) {
225 self.with_access(|a| a.set_state(AccessState::RowSpan(span)))
226 }
227
228 pub fn set_item_count(&mut self, count: usize) {
230 self.with_access(|a| a.set_state(AccessState::ItemCount(count)))
231 }
232
233 pub fn set_item_index(&mut self, index: usize) {
235 self.with_access(|a| a.set_state(AccessState::ItemIndex(index)))
236 }
237
238 pub fn flag_modal(&mut self) {
240 self.with_access(|a| a.set_state(AccessState::Modal))
241 }
242
243 pub fn set_lang(&mut self, lang: LanguageIdentifier) {
245 self.with_access(|a| a.set_state(AccessState::Lang(lang)))
246 }
247
248 pub fn set_scroll_horizontal(&mut self, normal_x: impl IntoVar<Factor>) {
257 let normal_x = normal_x.into_var();
258 self.with_access(|a| a.set_state_source(AccessStateSource::ScrollHorizontal(normal_x)))
259 }
260
261 pub fn set_scroll_vertical(&mut self, normal_y: impl IntoVar<Factor>) {
270 let normal_y = normal_y.into_var();
271 self.with_access(|a| a.set_state_source(AccessStateSource::ScrollVertical(normal_y)))
272 }
273
274 pub fn push_controls(&mut self, controlled_id: impl Into<WidgetId>) {
276 let controlled_id = controlled_id.into();
277 self.with_access(|a| {
278 for state in &mut a.state {
279 if let AccessState::Controls(c) = state {
280 c.push(controlled_id.into());
281 return;
282 }
283 }
284 a.state.push(AccessState::Controls(vec![controlled_id.into()]))
285 })
286 }
287
288 pub fn push_described_by(&mut self, descriptor_id: impl Into<WidgetId>) {
290 let descriptor_id = descriptor_id.into();
291 self.with_access(|a| {
292 for state in &mut a.state {
293 if let AccessState::DescribedBy(c) = state {
294 c.push(descriptor_id.into());
295 return;
296 }
297 }
298 a.state.push(AccessState::DescribedBy(vec![descriptor_id.into()]))
299 })
300 }
301
302 pub fn set_describes(&mut self, target_id: impl Into<WidgetId>) {
308 let target_id = target_id.into();
309 self.with_access(|a| {
310 for state in &mut a.inverse_state {
311 if let InverseAccessState::Describes(t) = state {
312 *t = target_id;
313 return;
314 }
315 }
316 a.inverse_state.push(InverseAccessState::Describes(target_id));
317 })
318 }
319
320 pub fn push_details(&mut self, detail_id: impl Into<WidgetId>) {
322 let detail_id = detail_id.into();
323 self.with_access(|a| {
324 for state in &mut a.state {
325 if let AccessState::Details(c) = state {
326 c.push(detail_id.into());
327 return;
328 }
329 }
330 a.state.push(AccessState::Details(vec![detail_id.into()]))
331 })
332 }
333
334 pub fn push_labelled_by(&mut self, label_id: impl Into<WidgetId>) {
336 let label_id = label_id.into();
337 self.with_access(|a| {
338 for state in &mut a.state {
339 if let AccessState::LabelledBy(c) = state {
340 c.push(label_id.into());
341 return;
342 }
343 }
344 a.state.push(AccessState::LabelledBy(vec![label_id.into()]))
345 })
346 }
347
348 pub fn set_labels(&mut self, target_id: impl Into<WidgetId>) {
354 let target_id = target_id.into();
355 self.with_access(|a| {
356 for state in &mut a.inverse_state {
357 if let InverseAccessState::Labels(t) = state {
358 *t = target_id;
359 return;
360 }
361 }
362 a.inverse_state.push(InverseAccessState::Labels(target_id));
363 })
364 }
365
366 pub fn push_owns(&mut self, owned_id: impl Into<WidgetId>) {
368 let owned_id = owned_id.into();
369 self.with_access(|a| {
370 for state in &mut a.state {
371 if let AccessState::Owns(c) = state {
372 c.push(owned_id.into());
373 return;
374 }
375 }
376 a.state.push(AccessState::Owns(vec![owned_id.into()]))
377 })
378 }
379
380 pub fn push_flows_to(&mut self, next_id: impl Into<WidgetId>) {
382 let next_id = next_id.into();
383 self.with_access(|a| {
384 for state in &mut a.state {
385 if let AccessState::FlowTo(c) = state {
386 c.push(next_id.into());
387 return;
388 }
389 }
390 a.state.push(AccessState::FlowTo(vec![next_id.into()]))
391 })
392 }
393
394 pub fn flag_labelled_by_child(&mut self) {
398 self.with_access(|a| a.set_state(AccessState::LabelledByChild))
399 }
400
401 pub fn flag_inaccessible(&mut self) {
406 self.builder.flag_meta(*INACCESSIBLE_ID);
407 }
408
409 pub fn on_access_build(&mut self, handler: impl Fn(AccessBuildArgs) + Send + Sync + 'static) {
412 let handler = Box::new(handler);
413 self.with_access(|a| a.build_handlers.push(handler));
414 }
415}
416
417impl WidgetInfoTree {
418 pub fn access_enabled(&self) -> AccessEnabled {
422 self.0.access_enabled
423 }
424
425 pub fn to_access_tree(&self) -> zng_view_api::access::AccessTree {
431 let mut builder = zng_view_api::access::AccessTreeBuilder::default();
432 if self.0.access_enabled.is_enabled() {
433 let inverse = self.collect_inverse_state();
435 self.root().access().unwrap().to_access_info(&inverse, &mut builder);
436 } else {
437 builder.push(zng_view_api::access::AccessNode::new(
438 self.root().id().into(),
439 Some(AccessRole::Application),
440 ));
441 }
442 builder.build()
443 }
444
445 pub fn to_access_updates(&self, prev_tree: &Self) -> Option<zng_view_api::access::AccessTreeUpdate> {
457 let is_enabled = self.access_enabled().is_enabled();
458 let root_id = self.root().id().into();
459 if is_enabled && !prev_tree.access_enabled().is_enabled() {
460 return Some(zng_view_api::access::AccessTreeUpdate::new(
462 vec![self.to_access_tree()],
463 Some(root_id),
464 root_id,
465 ));
466 }
467
468 if is_enabled {
469 let inverse = self.collect_inverse_state();
470 let mut updates = vec![];
471 self.root().access().unwrap().to_access_updates(prev_tree, &inverse, &mut updates);
472 if !updates.is_empty() {
473 return Some(zng_view_api::access::AccessTreeUpdate::new(updates, None, root_id));
474 }
475 }
476
477 None
478 }
479
480 pub fn to_access_updates_bounds(&self) -> Option<zng_view_api::access::AccessTreeUpdate> {
491 let is_enabled = self.access_enabled().is_enabled();
492 let root_id = self.root().id().into();
493
494 if is_enabled && {
495 let frame = self.0.frame.read();
496 frame.stats.bounds_updated_frame == frame.stats.last_frame || frame.stats.vis_updated_frame == frame.stats.last_frame
497 } {
498 let inverse = self.collect_inverse_state();
499 let mut updates = vec![];
500 self.root().access().unwrap().to_access_updates_bounds(&inverse, &mut updates);
501 if !updates.is_empty() {
502 return Some(zng_view_api::access::AccessTreeUpdate::new(updates, None, root_id));
503 }
504 }
505
506 None
507 }
508
509 fn collect_inverse_state(&self) -> InverseAccess {
510 let mut state = InverseAccess::default();
511 for wgt in self.root().self_and_descendants() {
512 if let Some(a) = wgt.access() {
513 if let Some(t) = a.labels() {
514 state.labelled_by.entry(t.id()).or_default().push(wgt.id());
515 }
516 if let Some(t) = a.describes() {
517 state.described_by.entry(t.id()).or_default().push(wgt.id());
518 }
519 }
520 }
521 state
522 }
523}
524
525impl WidgetInfo {
526 pub fn access(&self) -> Option<WidgetAccessInfo> {
532 if self.tree.access_enabled().is_enabled() && self.meta().contains(*ACCESS_INFO_ID) {
533 Some(WidgetAccessInfo { info: self.clone() })
534 } else {
535 None
536 }
537 }
538
539 pub fn access_children(&self) -> impl Iterator<Item = WidgetAccessInfo> {
543 self.descendants()
544 .tree_filter(|w| {
545 if w.access().is_some() {
546 super::TreeFilter::SkipDescendants
547 } else {
548 super::TreeFilter::Skip
549 }
550 })
551 .map(|w| w.access().unwrap())
552 }
553
554 fn access_children_ids(&self, is_prev: bool) -> Vec<zng_view_api::access::AccessNodeId> {
555 self.access_children()
556 .filter_map(|w| {
557 if w.is_local_accessible() {
558 if is_prev && w.access().view_bounds.lock().is_none() {
559 None
561 } else {
562 Some(w.info.id().into())
563 }
564 } else {
565 None
566 }
567 })
568 .collect()
569 }
570
571 pub fn access_parent(&self) -> Option<WidgetAccessInfo> {
573 self.ancestors().find_map(|w| w.access())
574 }
575}
576
577pub struct WidgetAccessInfo {
579 info: WidgetInfo,
580}
581macro_rules! get_state {
582 ($self:ident.$Discriminant:ident) => {
583 get_state!($self, state, AccessState, $Discriminant)
584 };
585 ($self:ident.source.$Discriminant:ident) => {
586 get_state!($self, state_source, AccessStateSource, $Discriminant)
587 };
588 ($self:ident.inverse.$Discriminant:ident) => {
589 get_state!($self, inverse_state, InverseAccessState, $Discriminant)
590 };
591 ($self:ident, $state:ident, $State:ident, $Discriminant:ident) => {
592 $self
593 .access()
594 .$state
595 .iter()
596 .find_map(|a| if let $State::$Discriminant(value) = a { Some(value) } else { None })
597 };
598}
599macro_rules! has_state {
600 ($self:ident.$Discriminant:ident) => {
601 $self.access().state.iter().any(|a| matches!(a, AccessState::$Discriminant))
602 };
603}
604macro_rules! get_widgets {
605 ($self:ident.$Discriminant:ident) => {
606 $self
607 .access()
608 .state
609 .iter()
610 .find_map(|a| {
611 if let AccessState::$Discriminant(ids) = a {
612 Some(ids.iter().filter_map(|id| {
613 let id = WidgetId::from_raw(id.0);
614 $self.info.tree.get(id)
615 }))
616 } else {
617 None
618 }
619 })
620 .into_iter()
621 .flatten()
622 };
623}
624impl WidgetAccessInfo {
625 pub fn info(&self) -> &WidgetInfo {
627 &self.info
628 }
629
630 fn access(&self) -> &AccessInfo {
631 self.info.meta().req(*ACCESS_INFO_ID)
632 }
633
634 pub fn role(&self) -> Option<AccessRole> {
636 self.access().role
637 }
638
639 pub fn commands(&self) -> &[AccessCmdName] {
641 &self.access().commands
642 }
643
644 pub fn auto_complete(&self) -> Option<AutoComplete> {
646 get_state!(self.AutoComplete).copied()
647 }
648
649 pub fn checked(&self) -> Option<Option<bool>> {
653 get_state!(self.Checked).copied()
654 }
655
656 pub fn current(&self) -> Option<CurrentKind> {
658 get_state!(self.Current).copied()
659 }
660
661 pub fn error_message(&self) -> Option<WidgetInfo> {
663 let id = get_state!(self.ErrorMessage)?;
664 let id = WidgetId::from_raw(id.0);
665 self.info.tree.get(id)
666 }
667
668 pub fn active_descendant(&self) -> Option<WidgetInfo> {
670 let id = get_state!(self.ActiveDescendant)?;
671 let id = WidgetId::from_raw(id.0);
672 self.info.tree.get(id)
673 }
674
675 pub fn expanded(&self) -> Option<bool> {
677 get_state!(self.Expanded).copied()
678 }
679
680 pub fn has_popup(&self) -> Option<Popup> {
682 get_state!(self.Popup).copied()
683 }
684
685 pub fn invalid(&self) -> Invalid {
687 get_state!(self.Invalid).copied().unwrap_or_else(Invalid::empty)
688 }
689
690 pub fn label(&self) -> Option<Txt> {
692 get_state!(self.source.Label).cloned()
693 }
694
695 pub fn labelled_by_child(&self) -> bool {
699 has_state!(self.LabelledByChild)
700 }
701
702 pub fn lang(&self) -> Option<LanguageIdentifier> {
706 get_state!(self.Lang).cloned()
707 }
708 pub fn scroll_horizontal(&self) -> Option<Var<Factor>> {
712 get_state!(self.source.ScrollHorizontal).cloned()
713 }
714 pub fn scroll_vertical(&self) -> Option<Var<Factor>> {
718 get_state!(self.source.ScrollVertical).cloned()
719 }
720
721 pub fn is_multi_selectable(&self) -> bool {
723 has_state!(self.MultiSelectable)
724 }
725
726 pub fn orientation(&self) -> Option<Orientation> {
728 get_state!(self.Orientation).copied()
729 }
730
731 pub fn placeholder(&self) -> Option<Txt> {
733 get_state!(self.source.Placeholder).cloned()
734 }
735
736 pub fn is_read_only(&self) -> bool {
738 has_state!(self.ReadOnly)
739 }
740
741 pub fn is_required(&self) -> bool {
743 has_state!(self.Required)
744 }
745
746 pub fn level(&self) -> Option<NonZeroU32> {
748 get_state!(self.Level).copied()
749 }
750
751 pub fn is_selected(&self) -> bool {
753 has_state!(self.Selected)
754 }
755
756 pub fn sort(&self) -> Option<SortDirection> {
758 get_state!(self.Sort).copied()
759 }
760
761 pub fn value_max(&self) -> Option<f64> {
763 get_state!(self.ValueMax).copied()
764 }
765
766 pub fn value_min(&self) -> Option<f64> {
768 get_state!(self.ValueMin).copied()
769 }
770
771 pub fn value(&self) -> Option<f64> {
773 get_state!(self.Value).copied()
774 }
775
776 pub fn value_text(&self) -> Option<Txt> {
783 get_state!(self.source.ValueText).cloned()
784 }
785
786 pub fn live(&self) -> Option<(LiveIndicator, bool, bool)> {
792 self.access().state.iter().find_map(|s| {
793 if let AccessState::Live { indicator, atomic, busy } = s {
794 Some((*indicator, *atomic, *busy))
795 } else {
796 None
797 }
798 })
799 }
800
801 pub fn col_count(&self) -> Option<usize> {
809 get_state!(self.ColCount).copied()
810 }
811
812 pub fn col_index(&self) -> Option<usize> {
814 get_state!(self.ColIndex).copied()
815 }
816
817 pub fn col_span(&self) -> Option<usize> {
819 get_state!(self.ColSpan).copied()
820 }
821
822 pub fn row_count(&self) -> Option<usize> {
830 get_state!(self.RowCount).copied()
831 }
832
833 pub fn row_index(&self) -> Option<usize> {
835 get_state!(self.RowIndex).copied()
836 }
837
838 pub fn row_span(&self) -> Option<usize> {
840 get_state!(self.RowSpan).copied()
841 }
842
843 pub fn item_count(&self) -> Option<usize> {
845 get_state!(self.ItemCount).copied()
846 }
847
848 pub fn item_index(&self) -> Option<usize> {
850 get_state!(self.ItemIndex).copied()
851 }
852
853 pub fn modal(&self) -> bool {
855 has_state!(self.Modal)
856 }
857
858 pub fn controls(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
860 get_widgets!(self.Controls)
861 }
862
863 pub fn described_by(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
865 get_widgets!(self.DescribedBy)
866 }
867
868 pub fn describes(&self) -> Option<WidgetInfo> {
875 get_state!(self.inverse.Describes).copied().and_then(|id| self.info.tree().get(id))
876 }
877
878 pub fn details(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
880 get_widgets!(self.Details)
881 }
882
883 pub fn labelled_by(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
885 get_widgets!(self.LabelledBy)
886 }
887
888 pub fn labels(&self) -> Option<WidgetInfo> {
895 get_state!(self.inverse.Labels).copied().and_then(|id| self.info.tree().get(id))
896 }
897
898 pub fn owns(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
900 get_widgets!(self.Owns)
901 }
902
903 pub fn flows_to(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
905 get_widgets!(self.FlowTo)
906 }
907
908 pub fn is_accessible(&self) -> bool {
913 for wgt in self.info.self_and_ancestors() {
914 if wgt.meta().contains(*INACCESSIBLE_ID) || !self.info.visibility().is_visible() {
915 return false;
916 }
917 }
918 true
919 }
920
921 fn is_local_accessible(&self) -> bool {
922 !self.info.meta().contains(*INACCESSIBLE_ID) && self.info.visibility().is_visible()
923 }
924
925 fn to_access_node_leaf(&self, inverse: &InverseAccess) -> zng_view_api::access::AccessNode {
926 let mut node = zng_view_api::access::AccessNode::new(self.info.id().into(), None);
927 let a = self.access();
928
929 let bounds_info = self.bounds_info();
930 node.transform = bounds_info.transform;
931 node.size = bounds_info.size;
932 *a.view_bounds.lock() = Some(bounds_info);
933
934 node.role = a.role;
935 node.state.clone_from(&a.state);
936 node.state.extend(a.state_source.iter().map(From::from));
937
938 if let Some(lb) = inverse.labelled_by.get(&self.info.id()) {
939 let mut done = false;
940 for state in node.state.iter_mut() {
941 if let AccessState::LabelledBy(l) = state {
942 l.extend(lb.iter().map(|&id| AccessNodeId::from(id)));
943 done = true;
944 break;
945 }
946 }
947 if !done {
948 node.state.push(AccessState::LabelledBy(lb.iter().map(|&id| id.into()).collect()));
949 }
950 }
951 if let Some(ds) = inverse.described_by.get(&self.info.id()) {
952 let mut done = false;
953 for state in node.state.iter_mut() {
954 if let AccessState::DescribedBy(l) = state {
955 l.extend(ds.iter().map(|&id| AccessNodeId::from(id)));
956 done = true;
957 break;
958 }
959 }
960 if !done {
961 node.state.push(AccessState::DescribedBy(ds.iter().map(|&id| id.into()).collect()));
962 }
963 }
964
965 node.commands.clone_from(&a.commands);
966
967 for handler in &a.build_handlers {
968 handler(AccessBuildArgs {
969 widget: self,
970 node: &mut node,
971 });
972 }
973
974 node
975 }
976
977 fn bounds_info(&self) -> ViewBoundsInfo {
978 let bounds = self.info.bounds_info();
979 let undo_parent_transform = self
980 .info
981 .access_parent()
982 .and_then(|w| w.info.inner_transform().inverse())
983 .unwrap_or_default();
984 let transform = bounds.inner_transform().then(&undo_parent_transform);
985 let size = bounds.inner_size();
986
987 let scroll_h = get_state!(self.source.ScrollHorizontal).map(|x| x.get());
988 let scroll_v = get_state!(self.source.ScrollVertical).map(|x| x.get());
989
990 ViewBoundsInfo {
991 transform,
992 size,
993 scroll_h,
994 scroll_v,
995 }
996 }
997
998 fn to_access_info(&self, inverse: &InverseAccess, builder: &mut zng_view_api::access::AccessTreeBuilder) -> bool {
999 if !self.is_local_accessible() {
1000 if self.info.parent().is_none() {
1001 builder.push(zng_view_api::access::AccessNode::new(self.info.id().into(), self.access().role));
1003 }
1004 *self.access().view_bounds.lock() = None;
1005 return false;
1006 }
1007
1008 let node = builder.push(self.to_access_node_leaf(inverse));
1009
1010 let mut children_len = 0;
1011 let len_before = builder.len();
1012 for child in self.info.access_children() {
1013 if child.to_access_info(inverse, builder) {
1014 children_len += 1;
1015 }
1016 }
1017 let descendants_len = (builder.len() - len_before) as u32;
1018
1019 let node = builder.node(node);
1020 node.children_len = children_len;
1021 node.descendants_len = descendants_len;
1022
1023 true
1024 }
1025
1026 fn to_access_updates(&self, prev_tree: &WidgetInfoTree, inverse: &InverseAccess, updates: &mut Vec<zng_view_api::access::AccessTree>) {
1027 if !self.is_local_accessible() {
1028 *self.access().view_bounds.lock() = None;
1030 return;
1031 }
1032
1033 let mut bounds_changed = false;
1034 let mut vis_changed = false;
1035 if self.info.is_reused() {
1036 let bounds = Some(self.bounds_info());
1039 let a = self.access();
1040 let mut prev_bounds = a.view_bounds.lock();
1041
1042 bounds_changed = *prev_bounds != bounds;
1043
1044 if !bounds_changed {
1045 return;
1046 }
1047
1048 vis_changed = prev_bounds.is_none() && bounds.is_some();
1049
1050 *prev_bounds = bounds;
1051 }
1052 let bounds_changed = bounds_changed;
1053 let vis_changed = vis_changed;
1054
1055 if let Some(prev) = prev_tree.get(self.info.id()) {
1056 let was_accessible = !vis_changed && prev.access().map(|w| w.is_local_accessible()).unwrap_or(false);
1057 if was_accessible && let Some(prev) = prev.access() {
1058 let mut children = None;
1059 if bounds_changed || !prev.access().info_eq(self.access()) || {
1060 let c = self.info.access_children_ids(false);
1062 let changed = c != prev.info.access_children_ids(true);
1063 children = Some(c);
1064 changed
1065 } {
1066 let mut node = self.to_access_node_leaf(inverse);
1068
1069 for child in self.info.access_children() {
1070 child.to_access_updates(prev_tree, inverse, updates);
1071 }
1072
1073 node.children = children.unwrap_or_else(|| {
1074 self.info
1075 .access_children()
1076 .filter_map(|a| if a.is_local_accessible() { Some(a.info.id().into()) } else { None })
1077 .collect()
1078 });
1079
1080 let mut builder = zng_view_api::access::AccessTreeBuilder::default();
1081 builder.push(node);
1082 updates.push(builder.build());
1083
1084 return;
1085 } else {
1086 for child in self.info.access_children() {
1089 child.to_access_updates(prev_tree, inverse, updates);
1090 }
1091
1092 return;
1093 }
1094 } else {
1095 }
1097 }
1098
1099 let mut builder = zng_view_api::access::AccessTreeBuilder::default();
1101 let insert = self.to_access_info(inverse, &mut builder);
1102 assert!(insert);
1103 updates.push(builder.build());
1104 }
1105
1106 fn to_access_updates_bounds(&self, inverse: &InverseAccess, updates: &mut Vec<zng_view_api::access::AccessTree>) -> bool {
1108 if self.info.meta().contains(*INACCESSIBLE_ID) {
1109 return false;
1111 }
1112 if !self.info.visibility().is_visible() {
1113 return self.access().view_bounds.lock().take().is_some();
1115 }
1116
1117 let a = self.access();
1118
1119 let mut vis_changed = false;
1120 let mut update;
1121
1122 let new_bounds = Some(self.bounds_info());
1123 {
1124 let mut bounds = a.view_bounds.lock();
1125 update = *bounds != new_bounds;
1126 if update {
1127 vis_changed = bounds.is_none();
1128 *bounds = new_bounds;
1129 }
1130 };
1131
1132 if vis_changed {
1133 let mut builder = zng_view_api::access::AccessTreeBuilder::default();
1135 let insert = self.to_access_info(inverse, &mut builder);
1136 assert!(insert);
1137 updates.push(builder.build());
1138 } else {
1139 for child in self.info.access_children() {
1142 let child_vis_changed = child.to_access_updates_bounds(inverse, updates);
1143 update |= child_vis_changed;
1144 }
1145
1146 if update {
1147 let mut node = self.to_access_node_leaf(inverse);
1148 node.children = self
1149 .info
1150 .access_children()
1151 .filter_map(|a| if a.is_local_accessible() { Some(a.info.id().into()) } else { None })
1152 .collect();
1153
1154 let mut builder = zng_view_api::access::AccessTreeBuilder::default();
1155 builder.push(node);
1156 updates.push(builder.build());
1157 }
1158 }
1159
1160 vis_changed
1161 }
1162}
1163
1164#[derive(PartialEq, Debug, Clone, Copy)]
1165struct ViewBoundsInfo {
1166 transform: PxTransform,
1167 size: PxSize,
1168 scroll_h: Option<Factor>,
1169 scroll_v: Option<Factor>,
1170}
1171
1172#[derive(Default)]
1173struct AccessInfo {
1174 role: Option<AccessRole>,
1175 commands: Vec<AccessCmdName>,
1176 state: Vec<AccessState>,
1177 state_source: Vec<AccessStateSource>,
1178 inverse_state: Vec<InverseAccessState>,
1179
1180 view_bounds: Mutex<Option<ViewBoundsInfo>>,
1181 build_handlers: Vec<Box<dyn Fn(AccessBuildArgs) + Send + Sync>>,
1182}
1183impl AccessInfo {
1184 fn set_state(&mut self, state: AccessState) {
1185 let discriminant = std::mem::discriminant(&state);
1186 if let Some(present) = self.state.iter_mut().find(|s| std::mem::discriminant(&**s) == discriminant) {
1187 *present = state;
1188 } else {
1189 self.state.push(state);
1190 }
1191 }
1192
1193 fn set_state_source(&mut self, state: AccessStateSource) {
1194 let discriminant = std::mem::discriminant(&state);
1195 if let Some(present) = self.state_source.iter_mut().find(|s| std::mem::discriminant(&**s) == discriminant) {
1196 *present = state;
1197 } else {
1198 self.state_source.push(state);
1199 }
1200 }
1201
1202 fn info_eq(&self, other: &Self) -> bool {
1203 self.role == other.role && self.commands == other.commands && self.state == other.state && self.state_source == other.state_source
1204 }
1205}
1206
1207enum AccessStateSource {
1208 Label(Txt),
1209 Placeholder(Txt),
1210 ValueText(Txt),
1211 ScrollHorizontal(Var<Factor>),
1212 ScrollVertical(Var<Factor>),
1213}
1214impl PartialEq for AccessStateSource {
1215 fn eq(&self, other: &Self) -> bool {
1216 match (self, other) {
1217 (Self::Label(l0), Self::Label(r0)) => l0 == r0,
1218 (Self::Placeholder(l0), Self::Placeholder(r0)) => l0 == r0,
1219 (Self::ValueText(l0), Self::ValueText(r0)) => l0 == r0,
1220 (Self::ScrollHorizontal(l0), Self::ScrollHorizontal(r0)) => l0.var_eq(r0),
1222 (Self::ScrollVertical(l0), Self::ScrollVertical(r0)) => l0.var_eq(r0),
1223 _ => false,
1224 }
1225 }
1226}
1227impl From<&AccessStateSource> for AccessState {
1228 fn from(value: &AccessStateSource) -> Self {
1229 match value {
1230 AccessStateSource::Label(l) => AccessState::Label(l.clone()),
1231 AccessStateSource::Placeholder(p) => AccessState::Placeholder(p.clone()),
1232 AccessStateSource::ValueText(v) => AccessState::ValueText(v.clone()),
1233 AccessStateSource::ScrollHorizontal(x) => AccessState::ScrollHorizontal(x.get().0),
1234 AccessStateSource::ScrollVertical(y) => AccessState::ScrollVertical(y.get().0),
1235 }
1236 }
1237}
1238
1239enum InverseAccessState {
1240 Labels(WidgetId),
1241 Describes(WidgetId),
1242}
1243
1244#[derive(Default)]
1245struct InverseAccess {
1246 labelled_by: IdMap<WidgetId, Vec<WidgetId>>,
1247 described_by: IdMap<WidgetId, Vec<WidgetId>>,
1248}
1249
1250static_id! {
1251 static ref ACCESS_INFO_ID: StateId<AccessInfo>;
1252 static ref INACCESSIBLE_ID: StateId<()>;
1253}
1254
1255bitflags::bitflags! {
1256 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
1258 #[serde(transparent)]
1259 pub struct AccessEnabled: u8 {
1260 const APP = 0b01;
1262 const VIEW = 0b11;
1264 }
1265}
1266impl AccessEnabled {
1267 pub fn is_enabled(self) -> bool {
1269 !self.is_empty()
1270 }
1271
1272 pub fn is_disabled(self) -> bool {
1274 self.is_empty()
1275 }
1276}
1277
1278#[non_exhaustive]
1282pub struct AccessBuildArgs<'a> {
1283 pub widget: &'a WidgetAccessInfo,
1285 pub node: &'a mut zng_view_api::access::AccessNode,
1287}