public override IEnumerable <FocusNode> sortDescendants(IEnumerable <FocusNode> descendants) { FocusTraversalPolicy secondaryPolicy = secondary ?? new ReadingOrderTraversalPolicy(); IEnumerable <FocusNode> sortedDescendants = secondaryPolicy.sortDescendants(descendants); List <FocusNode> unordered = new List <FocusNode>(); List <_OrderedFocusInfo> ordered = new List <_OrderedFocusInfo>(); foreach (FocusNode node in sortedDescendants) { FocusOrder order = FocusTraversalOrder.of(node.context, nullOk: true); if (order != null) { ordered.Add(new _OrderedFocusInfo(node: node, order: order)); } else { unordered.Add(node); } } FocusTravesalUtils.mergeSort <_OrderedFocusInfo>(ordered, compare: (_OrderedFocusInfo a, _OrderedFocusInfo b) => { D.assert( a.order.GetType() == b.order.GetType(), () => $"When sorting nodes for determining focus order, the order ({a.order}) of " + $"node {a.node}, isn't the same type as the order ({b.order}) of {b.node}. " + "Incompatible order types can't be compared. Use a FocusTraversalGroup to group " + "similar orders together." ); return(a.order.CompareTo(b.order)); }); return(LinqUtils <FocusNode, _OrderedFocusInfo> .SelectList(ordered, ((_OrderedFocusInfo info) => info.node)).Concat(unordered)); }
public FocusTraversalGroup( Key key = null, FocusTraversalPolicy policy = null, Widget child = null ) : base(key: key) { this.policy = policy ?? new ReadingOrderTraversalPolicy(); this.child = child; }
public _FocusTraversalGroupInfo( _FocusTraversalGroupMarker marker, FocusTraversalPolicy defaultPolicy = null, List <FocusNode> members = null ) { groupNode = marker?.focusNode; policy = marker?.policy ?? defaultPolicy ?? new ReadingOrderTraversalPolicy(); this.members = members ?? new List <FocusNode>(); }
public _FocusTraversalGroupMarker( FocusTraversalPolicy policy = null, FocusNode focusNode = null, Widget child = null ) : base(child: child) { D.assert(policy != null); D.assert(focusNode != null); this.policy = policy; this.focusNode = focusNode; }
public OrderedTraversalPolicy(FocusTraversalPolicy secondary) { this.secondary = secondary; }
public List <FocusNode> _sortAllDescendants(FocusScopeNode scope) { D.assert(scope != null); _FocusTraversalGroupMarker scopeGroupMarker = _getMarker(scope.context); FocusTraversalPolicy defaultPolicy = scopeGroupMarker?.policy ?? new ReadingOrderTraversalPolicy(); Dictionary <FocusNode, _FocusTraversalGroupInfo> groups = new Dictionary <FocusNode, _FocusTraversalGroupInfo>(); foreach (FocusNode node in scope.descendants) { _FocusTraversalGroupMarker groupMarker = _getMarker(node.context); FocusNode groupNode = groupMarker?.focusNode; if (node == groupNode) { BuildContext parentContext = FocusTravesalUtils._getAncestor(groupNode.context, count: 2); _FocusTraversalGroupMarker parentMarker = _getMarker(parentContext); FocusNode parentNode = parentMarker?.focusNode; groups[groupNode] = groups.getOrDefault(parentNode) ?? new _FocusTraversalGroupInfo(parentMarker, members: new List <FocusNode>(), defaultPolicy: defaultPolicy); D.assert(!groups[parentNode].members.Contains(node)); groups[parentNode].members.Add(groupNode); continue; } if (node.canRequestFocus && !node.skipTraversal) { groups[groupNode] = groups.getOrDefault(groupNode) ?? new _FocusTraversalGroupInfo(groupMarker, members: new List <FocusNode>(), defaultPolicy: defaultPolicy); D.assert(!groups[groupNode].members.Contains(node)); groups[groupNode].members.Add(node); } } HashSet <FocusNode> groupKeys = new HashSet <FocusNode>(groups.Keys); foreach (FocusNode key in groups.Keys) { List <FocusNode> sortedMembers = groups.getOrDefault(key).policy.sortDescendants(groups.getOrDefault(key).members).ToList(); groups[key].members.Clear(); groups[key].members.AddRange(sortedMembers); } List <FocusNode> sortedDescendants = new List <FocusNode>(); void visitGroups(_FocusTraversalGroupInfo info) { foreach (FocusNode node in info.members) { if (groupKeys.Contains(node)) { visitGroups(groups[node]); } else { sortedDescendants.Add(node); } } } visitGroups(groups[scopeGroupMarker?.focusNode]); D.assert( FocusTravesalUtils.difference(new HashSet <FocusNode>(sortedDescendants), (new HashSet <FocusNode>(scope.traversalDescendants))).isEmpty(), () => $"sorted descendants contains more nodes than it should: ({FocusTravesalUtils.difference(new HashSet<FocusNode>(sortedDescendants),(new HashSet<FocusNode>(scope.traversalDescendants)))})" ); D.assert( FocusTravesalUtils.difference(new HashSet <FocusNode>(scope.traversalDescendants), new HashSet <FocusNode>(sortedDescendants)).isEmpty(), () => $"sorted descendants are missing some nodes: ({FocusTravesalUtils.difference(new HashSet<FocusNode>(scope.traversalDescendants),new HashSet<FocusNode>(sortedDescendants))})" ); return(sortedDescendants); }