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::{BoxedVar, 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().boxed();
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().boxed();
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 {
462 updates: vec![self.to_access_tree()],
463 full_root: Some(root_id),
464 focused: 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 {
474 updates,
475 full_root: None,
476 focused: root_id,
477 });
478 }
479 }
480
481 None
482 }
483
484 pub fn to_access_updates_bounds(&self) -> Option<zng_view_api::access::AccessTreeUpdate> {
495 let is_enabled = self.access_enabled().is_enabled();
496 let root_id = self.root().id().into();
497
498 if is_enabled && {
499 let frame = self.0.frame.read();
500 frame.stats.bounds_updated_frame == frame.stats.last_frame || frame.stats.vis_updated_frame == frame.stats.last_frame
501 } {
502 let inverse = self.collect_inverse_state();
503 let mut updates = vec![];
504 self.root().access().unwrap().to_access_updates_bounds(&inverse, &mut updates);
505 if !updates.is_empty() {
506 return Some(zng_view_api::access::AccessTreeUpdate {
507 updates,
508 full_root: None,
509 focused: root_id,
510 });
511 }
512 }
513
514 None
515 }
516
517 fn collect_inverse_state(&self) -> InverseAccess {
518 let mut state = InverseAccess::default();
519 for wgt in self.root().self_and_descendants() {
520 if let Some(a) = wgt.access() {
521 if let Some(t) = a.labels() {
522 state.labelled_by.entry(t.id()).or_default().push(wgt.id());
523 }
524 if let Some(t) = a.describes() {
525 state.described_by.entry(t.id()).or_default().push(wgt.id());
526 }
527 }
528 }
529 state
530 }
531}
532
533impl WidgetInfo {
534 pub fn access(&self) -> Option<WidgetAccessInfo> {
540 if self.tree.access_enabled().is_enabled() && self.meta().contains(*ACCESS_INFO_ID) {
541 Some(WidgetAccessInfo { info: self.clone() })
542 } else {
543 None
544 }
545 }
546
547 pub fn access_children(&self) -> impl Iterator<Item = WidgetAccessInfo> {
551 self.descendants()
552 .tree_filter(|w| {
553 if w.access().is_some() {
554 super::TreeFilter::SkipDescendants
555 } else {
556 super::TreeFilter::Skip
557 }
558 })
559 .map(|w| w.access().unwrap())
560 }
561
562 fn access_children_ids(&self, is_prev: bool) -> Vec<zng_view_api::access::AccessNodeId> {
563 self.access_children()
564 .filter_map(|w| {
565 if w.is_local_accessible() {
566 if is_prev && w.access().view_bounds.lock().is_none() {
567 None
569 } else {
570 Some(w.info.id().into())
571 }
572 } else {
573 None
574 }
575 })
576 .collect()
577 }
578
579 pub fn access_parent(&self) -> Option<WidgetAccessInfo> {
581 self.ancestors().find_map(|w| w.access())
582 }
583}
584
585pub struct WidgetAccessInfo {
587 info: WidgetInfo,
588}
589macro_rules! get_state {
590 ($self:ident.$Discriminant:ident) => {
591 get_state!($self, state, AccessState, $Discriminant)
592 };
593 ($self:ident.source.$Discriminant:ident) => {
594 get_state!($self, state_source, AccessStateSource, $Discriminant)
595 };
596 ($self:ident.inverse.$Discriminant:ident) => {
597 get_state!($self, inverse_state, InverseAccessState, $Discriminant)
598 };
599 ($self:ident, $state:ident, $State:ident, $Discriminant:ident) => {
600 $self
601 .access()
602 .$state
603 .iter()
604 .find_map(|a| if let $State::$Discriminant(value) = a { Some(value) } else { None })
605 };
606}
607macro_rules! has_state {
608 ($self:ident.$Discriminant:ident) => {
609 $self.access().state.iter().any(|a| matches!(a, AccessState::$Discriminant))
610 };
611}
612macro_rules! get_widgets {
613 ($self:ident.$Discriminant:ident) => {
614 $self
615 .access()
616 .state
617 .iter()
618 .find_map(|a| {
619 if let AccessState::$Discriminant(ids) = a {
620 Some(ids.iter().filter_map(|id| {
621 let id = WidgetId::from_raw(id.0);
622 $self.info.tree.get(id)
623 }))
624 } else {
625 None
626 }
627 })
628 .into_iter()
629 .flatten()
630 };
631}
632impl WidgetAccessInfo {
633 pub fn info(&self) -> &WidgetInfo {
635 &self.info
636 }
637
638 fn access(&self) -> &AccessInfo {
639 self.info.meta().req(*ACCESS_INFO_ID)
640 }
641
642 pub fn role(&self) -> Option<AccessRole> {
644 self.access().role
645 }
646
647 pub fn commands(&self) -> &[AccessCmdName] {
649 &self.access().commands
650 }
651
652 pub fn auto_complete(&self) -> Option<AutoComplete> {
654 get_state!(self.AutoComplete).copied()
655 }
656
657 pub fn checked(&self) -> Option<Option<bool>> {
661 get_state!(self.Checked).copied()
662 }
663
664 pub fn current(&self) -> Option<CurrentKind> {
666 get_state!(self.Current).copied()
667 }
668
669 pub fn error_message(&self) -> Option<WidgetInfo> {
671 let id = get_state!(self.ErrorMessage)?;
672 let id = WidgetId::from_raw(id.0);
673 self.info.tree.get(id)
674 }
675
676 pub fn active_descendant(&self) -> Option<WidgetInfo> {
678 let id = get_state!(self.ActiveDescendant)?;
679 let id = WidgetId::from_raw(id.0);
680 self.info.tree.get(id)
681 }
682
683 pub fn expanded(&self) -> Option<bool> {
685 get_state!(self.Expanded).copied()
686 }
687
688 pub fn has_popup(&self) -> Option<Popup> {
690 get_state!(self.Popup).copied()
691 }
692
693 pub fn invalid(&self) -> Invalid {
695 get_state!(self.Invalid).copied().unwrap_or_else(Invalid::empty)
696 }
697
698 pub fn label(&self) -> Option<Txt> {
700 get_state!(self.source.Label).cloned()
701 }
702
703 pub fn labelled_by_child(&self) -> bool {
707 has_state!(self.LabelledByChild)
708 }
709
710 pub fn lang(&self) -> Option<LanguageIdentifier> {
714 get_state!(self.Lang).cloned()
715 }
716 pub fn scroll_horizontal(&self) -> Option<BoxedVar<Factor>> {
720 get_state!(self.source.ScrollHorizontal).cloned()
721 }
722 pub fn scroll_vertical(&self) -> Option<BoxedVar<Factor>> {
726 get_state!(self.source.ScrollVertical).cloned()
727 }
728
729 pub fn is_multi_selectable(&self) -> bool {
731 has_state!(self.MultiSelectable)
732 }
733
734 pub fn orientation(&self) -> Option<Orientation> {
736 get_state!(self.Orientation).copied()
737 }
738
739 pub fn placeholder(&self) -> Option<Txt> {
741 get_state!(self.source.Placeholder).cloned()
742 }
743
744 pub fn is_read_only(&self) -> bool {
746 has_state!(self.ReadOnly)
747 }
748
749 pub fn is_required(&self) -> bool {
751 has_state!(self.Required)
752 }
753
754 pub fn level(&self) -> Option<NonZeroU32> {
756 get_state!(self.Level).copied()
757 }
758
759 pub fn is_selected(&self) -> bool {
761 has_state!(self.Selected)
762 }
763
764 pub fn sort(&self) -> Option<SortDirection> {
766 get_state!(self.Sort).copied()
767 }
768
769 pub fn value_max(&self) -> Option<f64> {
771 get_state!(self.ValueMax).copied()
772 }
773
774 pub fn value_min(&self) -> Option<f64> {
776 get_state!(self.ValueMin).copied()
777 }
778
779 pub fn value(&self) -> Option<f64> {
781 get_state!(self.Value).copied()
782 }
783
784 pub fn value_text(&self) -> Option<Txt> {
791 get_state!(self.source.ValueText).cloned()
792 }
793
794 pub fn live(&self) -> Option<(LiveIndicator, bool, bool)> {
800 self.access().state.iter().find_map(|s| {
801 if let AccessState::Live { indicator, atomic, busy } = s {
802 Some((*indicator, *atomic, *busy))
803 } else {
804 None
805 }
806 })
807 }
808
809 pub fn col_count(&self) -> Option<usize> {
817 get_state!(self.ColCount).copied()
818 }
819
820 pub fn col_index(&self) -> Option<usize> {
822 get_state!(self.ColIndex).copied()
823 }
824
825 pub fn col_span(&self) -> Option<usize> {
827 get_state!(self.ColSpan).copied()
828 }
829
830 pub fn row_count(&self) -> Option<usize> {
838 get_state!(self.RowCount).copied()
839 }
840
841 pub fn row_index(&self) -> Option<usize> {
843 get_state!(self.RowIndex).copied()
844 }
845
846 pub fn row_span(&self) -> Option<usize> {
848 get_state!(self.RowSpan).copied()
849 }
850
851 pub fn item_count(&self) -> Option<usize> {
853 get_state!(self.ItemCount).copied()
854 }
855
856 pub fn item_index(&self) -> Option<usize> {
858 get_state!(self.ItemIndex).copied()
859 }
860
861 pub fn modal(&self) -> bool {
863 has_state!(self.Modal)
864 }
865
866 pub fn controls(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
868 get_widgets!(self.Controls)
869 }
870
871 pub fn described_by(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
873 get_widgets!(self.DescribedBy)
874 }
875
876 pub fn describes(&self) -> Option<WidgetInfo> {
883 get_state!(self.inverse.Describes).copied().and_then(|id| self.info.tree().get(id))
884 }
885
886 pub fn details(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
888 get_widgets!(self.Details)
889 }
890
891 pub fn labelled_by(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
893 get_widgets!(self.LabelledBy)
894 }
895
896 pub fn labels(&self) -> Option<WidgetInfo> {
903 get_state!(self.inverse.Labels).copied().and_then(|id| self.info.tree().get(id))
904 }
905
906 pub fn owns(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
908 get_widgets!(self.Owns)
909 }
910
911 pub fn flows_to(&self) -> impl Iterator<Item = WidgetInfo> + '_ {
913 get_widgets!(self.FlowTo)
914 }
915
916 pub fn is_accessible(&self) -> bool {
921 for wgt in self.info.self_and_ancestors() {
922 if wgt.meta().contains(*INACCESSIBLE_ID) || !self.info.visibility().is_visible() {
923 return false;
924 }
925 }
926 true
927 }
928
929 fn is_local_accessible(&self) -> bool {
930 !self.info.meta().contains(*INACCESSIBLE_ID) && self.info.visibility().is_visible()
931 }
932
933 fn to_access_node_leaf(&self, inverse: &InverseAccess) -> zng_view_api::access::AccessNode {
934 let mut node = zng_view_api::access::AccessNode::new(self.info.id().into(), None);
935 let a = self.access();
936
937 let bounds_info = self.bounds_info();
938 node.transform = bounds_info.transform;
939 node.size = bounds_info.size;
940 *a.view_bounds.lock() = Some(bounds_info);
941
942 node.role = a.role;
943 node.state.clone_from(&a.state);
944 node.state.extend(a.state_source.iter().map(From::from));
945
946 if let Some(lb) = inverse.labelled_by.get(&self.info.id()) {
947 let mut done = false;
948 for state in node.state.iter_mut() {
949 if let AccessState::LabelledBy(l) = state {
950 l.extend(lb.iter().map(|&id| AccessNodeId::from(id)));
951 done = true;
952 break;
953 }
954 }
955 if !done {
956 node.state.push(AccessState::LabelledBy(lb.iter().map(|&id| id.into()).collect()));
957 }
958 }
959 if let Some(ds) = inverse.described_by.get(&self.info.id()) {
960 let mut done = false;
961 for state in node.state.iter_mut() {
962 if let AccessState::DescribedBy(l) = state {
963 l.extend(ds.iter().map(|&id| AccessNodeId::from(id)));
964 done = true;
965 break;
966 }
967 }
968 if !done {
969 node.state.push(AccessState::DescribedBy(ds.iter().map(|&id| id.into()).collect()));
970 }
971 }
972
973 node.commands.clone_from(&a.commands);
974
975 for handler in &a.build_handlers {
976 handler(AccessBuildArgs {
977 widget: self,
978 node: &mut node,
979 });
980 }
981
982 node
983 }
984
985 fn bounds_info(&self) -> ViewBoundsInfo {
986 let bounds = self.info.bounds_info();
987 let undo_parent_transform = self
988 .info
989 .access_parent()
990 .and_then(|w| w.info.inner_transform().inverse())
991 .unwrap_or_default();
992 let transform = bounds.inner_transform().then(&undo_parent_transform);
993 let size = bounds.inner_size();
994
995 let scroll_h = get_state!(self.source.ScrollHorizontal).map(|x| x.get());
996 let scroll_v = get_state!(self.source.ScrollVertical).map(|x| x.get());
997
998 ViewBoundsInfo {
999 transform,
1000 size,
1001 scroll_h,
1002 scroll_v,
1003 }
1004 }
1005
1006 fn to_access_info(&self, inverse: &InverseAccess, builder: &mut zng_view_api::access::AccessTreeBuilder) -> bool {
1007 if !self.is_local_accessible() {
1008 if self.info.parent().is_none() {
1009 builder.push(zng_view_api::access::AccessNode::new(self.info.id().into(), self.access().role));
1011 }
1012 *self.access().view_bounds.lock() = None;
1013 return false;
1014 }
1015
1016 let node = builder.push(self.to_access_node_leaf(inverse));
1017
1018 let mut children_len = 0;
1019 let len_before = builder.len();
1020 for child in self.info.access_children() {
1021 if child.to_access_info(inverse, builder) {
1022 children_len += 1;
1023 }
1024 }
1025 let descendants_len = (builder.len() - len_before) as u32;
1026
1027 let node = builder.node(node);
1028 node.children_len = children_len;
1029 node.descendants_len = descendants_len;
1030
1031 true
1032 }
1033
1034 fn to_access_updates(&self, prev_tree: &WidgetInfoTree, inverse: &InverseAccess, updates: &mut Vec<zng_view_api::access::AccessTree>) {
1035 if !self.is_local_accessible() {
1036 *self.access().view_bounds.lock() = None;
1038 return;
1039 }
1040
1041 let mut bounds_changed = false;
1042 let mut vis_changed = false;
1043 if self.info.is_reused() {
1044 let bounds = Some(self.bounds_info());
1047 let a = self.access();
1048 let mut prev_bounds = a.view_bounds.lock();
1049
1050 bounds_changed = *prev_bounds != bounds;
1051
1052 if !bounds_changed {
1053 return;
1054 }
1055
1056 vis_changed = prev_bounds.is_none() && bounds.is_some();
1057
1058 *prev_bounds = bounds;
1059 }
1060 let bounds_changed = bounds_changed;
1061 let vis_changed = vis_changed;
1062
1063 if let Some(prev) = prev_tree.get(self.info.id()) {
1064 let was_accessible = !vis_changed && prev.access().map(|w| w.is_local_accessible()).unwrap_or(false);
1065 if let (true, Some(prev)) = (was_accessible, prev.access()) {
1066 let mut children = None;
1067 if bounds_changed || !prev.access().info_eq(self.access()) || {
1068 let c = self.info.access_children_ids(false);
1070 let changed = c != prev.info.access_children_ids(true);
1071 children = Some(c);
1072 changed
1073 } {
1074 let mut node = self.to_access_node_leaf(inverse);
1076
1077 for child in self.info.access_children() {
1078 child.to_access_updates(prev_tree, inverse, updates);
1079 }
1080
1081 node.children = children.unwrap_or_else(|| {
1082 self.info
1083 .access_children()
1084 .filter_map(|a| if a.is_local_accessible() { Some(a.info.id().into()) } else { None })
1085 .collect()
1086 });
1087
1088 let mut builder = zng_view_api::access::AccessTreeBuilder::default();
1089 builder.push(node);
1090 updates.push(builder.build());
1091
1092 return;
1093 } else {
1094 for child in self.info.access_children() {
1097 child.to_access_updates(prev_tree, inverse, updates);
1098 }
1099
1100 return;
1101 }
1102 } else {
1103 }
1105 }
1106
1107 let mut builder = zng_view_api::access::AccessTreeBuilder::default();
1109 let insert = self.to_access_info(inverse, &mut builder);
1110 assert!(insert);
1111 updates.push(builder.build());
1112 }
1113
1114 fn to_access_updates_bounds(&self, inverse: &InverseAccess, updates: &mut Vec<zng_view_api::access::AccessTree>) -> bool {
1116 if self.info.meta().contains(*INACCESSIBLE_ID) {
1117 return false;
1119 }
1120 if !self.info.visibility().is_visible() {
1121 return self.access().view_bounds.lock().take().is_some();
1123 }
1124
1125 let a = self.access();
1126
1127 let mut vis_changed = false;
1128 let mut update;
1129
1130 let new_bounds = Some(self.bounds_info());
1131 {
1132 let mut bounds = a.view_bounds.lock();
1133 update = *bounds != new_bounds;
1134 if update {
1135 vis_changed = bounds.is_none();
1136 *bounds = new_bounds;
1137 }
1138 };
1139
1140 if vis_changed {
1141 let mut builder = zng_view_api::access::AccessTreeBuilder::default();
1143 let insert = self.to_access_info(inverse, &mut builder);
1144 assert!(insert);
1145 updates.push(builder.build());
1146 } else {
1147 for child in self.info.access_children() {
1150 let child_vis_changed = child.to_access_updates_bounds(inverse, updates);
1151 update |= child_vis_changed;
1152 }
1153
1154 if update {
1155 let mut node = self.to_access_node_leaf(inverse);
1156 node.children = self
1157 .info
1158 .access_children()
1159 .filter_map(|a| if a.is_local_accessible() { Some(a.info.id().into()) } else { None })
1160 .collect();
1161
1162 let mut builder = zng_view_api::access::AccessTreeBuilder::default();
1163 builder.push(node);
1164 updates.push(builder.build());
1165 }
1166 }
1167
1168 vis_changed
1169 }
1170}
1171
1172#[derive(PartialEq, Debug, Clone, Copy)]
1173struct ViewBoundsInfo {
1174 transform: PxTransform,
1175 size: PxSize,
1176 scroll_h: Option<Factor>,
1177 scroll_v: Option<Factor>,
1178}
1179
1180#[derive(Default)]
1181struct AccessInfo {
1182 role: Option<AccessRole>,
1183 commands: Vec<AccessCmdName>,
1184 state: Vec<AccessState>,
1185 state_source: Vec<AccessStateSource>,
1186 inverse_state: Vec<InverseAccessState>,
1187
1188 view_bounds: Mutex<Option<ViewBoundsInfo>>,
1189 build_handlers: Vec<Box<dyn Fn(AccessBuildArgs) + Send + Sync>>,
1190}
1191impl AccessInfo {
1192 fn set_state(&mut self, state: AccessState) {
1193 let discriminant = std::mem::discriminant(&state);
1194 if let Some(present) = self.state.iter_mut().find(|s| std::mem::discriminant(&**s) == discriminant) {
1195 *present = state;
1196 } else {
1197 self.state.push(state);
1198 }
1199 }
1200
1201 fn set_state_source(&mut self, state: AccessStateSource) {
1202 let discriminant = std::mem::discriminant(&state);
1203 if let Some(present) = self.state_source.iter_mut().find(|s| std::mem::discriminant(&**s) == discriminant) {
1204 *present = state;
1205 } else {
1206 self.state_source.push(state);
1207 }
1208 }
1209
1210 fn info_eq(&self, other: &Self) -> bool {
1211 self.role == other.role && self.commands == other.commands && self.state == other.state && self.state_source == other.state_source
1212 }
1213}
1214
1215enum AccessStateSource {
1216 Label(Txt),
1217 Placeholder(Txt),
1218 ValueText(Txt),
1219 ScrollHorizontal(BoxedVar<Factor>),
1220 ScrollVertical(BoxedVar<Factor>),
1221}
1222impl PartialEq for AccessStateSource {
1223 fn eq(&self, other: &Self) -> bool {
1224 match (self, other) {
1225 (Self::Label(l0), Self::Label(r0)) => l0 == r0,
1226 (Self::Placeholder(l0), Self::Placeholder(r0)) => l0 == r0,
1227 (Self::ValueText(l0), Self::ValueText(r0)) => l0 == r0,
1228 (Self::ScrollHorizontal(l0), Self::ScrollHorizontal(r0)) => l0.var_ptr() == r0.var_ptr(),
1230 (Self::ScrollVertical(l0), Self::ScrollVertical(r0)) => l0.var_ptr() == r0.var_ptr(),
1231 _ => false,
1232 }
1233 }
1234}
1235impl From<&AccessStateSource> for AccessState {
1236 fn from(value: &AccessStateSource) -> Self {
1237 match value {
1238 AccessStateSource::Label(l) => AccessState::Label(l.clone()),
1239 AccessStateSource::Placeholder(p) => AccessState::Placeholder(p.clone()),
1240 AccessStateSource::ValueText(v) => AccessState::ValueText(v.clone()),
1241 AccessStateSource::ScrollHorizontal(x) => AccessState::ScrollHorizontal(x.get().0),
1242 AccessStateSource::ScrollVertical(y) => AccessState::ScrollVertical(y.get().0),
1243 }
1244 }
1245}
1246
1247enum InverseAccessState {
1248 Labels(WidgetId),
1249 Describes(WidgetId),
1250}
1251
1252#[derive(Default)]
1253struct InverseAccess {
1254 labelled_by: IdMap<WidgetId, Vec<WidgetId>>,
1255 described_by: IdMap<WidgetId, Vec<WidgetId>>,
1256}
1257
1258static_id! {
1259 static ref ACCESS_INFO_ID: StateId<AccessInfo>;
1260 static ref INACCESSIBLE_ID: StateId<()>;
1261}
1262
1263bitflags::bitflags! {
1264 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
1266 #[serde(transparent)]
1267 pub struct AccessEnabled: u8 {
1268 const APP = 0b01;
1270 const VIEW = 0b11;
1272 }
1273}
1274impl AccessEnabled {
1275 pub fn is_enabled(self) -> bool {
1277 !self.is_empty()
1278 }
1279
1280 pub fn is_disabled(self) -> bool {
1282 self.is_empty()
1283 }
1284}
1285
1286pub struct AccessBuildArgs<'a> {
1290 pub widget: &'a WidgetAccessInfo,
1292 pub node: &'a mut zng_view_api::access::AccessNode,
1294}