Shiyun Wen
4 年前
当前提交
456e8c67
共有 12 个文件被更改,包括 1130 次插入 和 597 次删除
-
30com.unity.uiwidgets/Runtime/foundation/diagnostics.cs
-
31com.unity.uiwidgets/Runtime/rendering/proxy_box.cs
-
13com.unity.uiwidgets/Runtime/rendering/proxy_sliver.cs
-
63com.unity.uiwidgets/Runtime/rendering/sliver.cs
-
642com.unity.uiwidgets/Runtime/widgets/focus_manager.cs
-
472com.unity.uiwidgets/Runtime/widgets/focus_traversal.cs
-
6com.unity.uiwidgets/Runtime/widgets/scroll_notification.mixin.njk
-
6com.unity.uiwidgets/Runtime/widgets/selectable_text.cs
-
13com.unity.uiwidgets/Runtime/widgets/transitions.cs
-
72com.unity.uiwidgets/Runtime/widgets/DiagnosticableTree.mixin.gen.cs
-
69com.unity.uiwidgets/Runtime/widgets/DiagnosticableTree.mixin.njk
-
310com.unity.uiwidgets/Runtime/widgets/DirectionalFocusTraversalPolicy.mixin.njk
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using Unity.UIWidgets.ui; |
|||
using UnityEngine; |
|||
namespace Unity.UIWidgets.foundation { |
|||
public class DiagnosticableTreeMixinChangeNotifier : ChangeNotifier, DiagnosticableTreeMixin { |
|||
protected DiagnosticableTreeMixinChangeNotifier() { |
|||
} |
|||
public virtual string toString( DiagnosticLevel minLevel = DiagnosticLevel.info ) { |
|||
return toDiagnosticsNode(style: DiagnosticsTreeStyle.singleLine).toString(minLevel: minLevel); |
|||
} |
|||
|
|||
public virtual string toStringShallow( |
|||
string joiner = ", ", |
|||
DiagnosticLevel minLevel = DiagnosticLevel.debug |
|||
) { |
|||
if (foundation_.kReleaseMode) { |
|||
return toString(); |
|||
} |
|||
string shallowString = ""; |
|||
D.assert(() => { |
|||
var result = new StringBuilder(); |
|||
result.Append(toString()); |
|||
result.Append(joiner); |
|||
DiagnosticPropertiesBuilder builder = new DiagnosticPropertiesBuilder(); |
|||
debugFillProperties(builder); |
|||
result.Append(string.Join(joiner, |
|||
builder.properties.Where(n => !n.isFiltered(minLevel)).Select(n => n.ToString()).ToArray()) |
|||
); |
|||
shallowString = result.ToString(); |
|||
return true; |
|||
}); |
|||
return shallowString; |
|||
} |
|||
|
|||
public virtual string toStringDeep( |
|||
string prefixLineOne = "", |
|||
string prefixOtherLines = null, |
|||
DiagnosticLevel minLevel = DiagnosticLevel.debug |
|||
) { |
|||
return toDiagnosticsNode().toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines, minLevel: minLevel); |
|||
} |
|||
|
|||
public virtual string toStringShort() { |
|||
return foundation_.describeIdentity(this); |
|||
} |
|||
|
|||
public virtual DiagnosticsNode toDiagnosticsNode( |
|||
string name = null, |
|||
DiagnosticsTreeStyle style = DiagnosticsTreeStyle.sparse) { |
|||
return new DiagnosticableTreeNode( |
|||
name: name, |
|||
value: this, |
|||
style: style |
|||
); |
|||
} |
|||
|
|||
public virtual List<DiagnosticsNode> debugDescribeChildren() |
|||
{ |
|||
return new List<DiagnosticsNode>(); |
|||
} |
|||
|
|||
public virtual void debugFillProperties(DiagnosticPropertiesBuilder properties) { } |
|||
|
|||
|
|||
|
|||
} |
|||
|
|||
} |
|||
|
|
|||
namespace Unity.UIWidgets.foundation { |
|||
{% macro DiagnosticableTreeMixin(with) %} |
|||
{% set className = 'DiagnosticableTreeMixin' + with %} |
|||
public class {{className}} : {{with}}, DiagnosticableTreeMixin { |
|||
protected {{className}}() { |
|||
} |
|||
public virtual string toString( DiagnosticLevel minLevel = DiagnosticLevel.info ) { |
|||
return toDiagnosticsNode(style: DiagnosticsTreeStyle.singleLine).toString(minLevel: minLevel); |
|||
} |
|||
|
|||
public virtual string toStringShallow( |
|||
string joiner = ", ", |
|||
DiagnosticLevel minLevel = DiagnosticLevel.debug |
|||
) { |
|||
if (foundation_.kReleaseMode) { |
|||
return toString(); |
|||
} |
|||
string shallowString = ""; |
|||
D.assert(() => { |
|||
var result = new StringBuilder(); |
|||
result.Append(toString()); |
|||
result.Append(joiner); |
|||
DiagnosticPropertiesBuilder builder = new DiagnosticPropertiesBuilder(); |
|||
debugFillProperties(builder); |
|||
result.Append(string.Join(joiner, |
|||
builder.properties.Where(n => !n.isFiltered(minLevel)).Select(n => n.ToString()).ToArray()) |
|||
); |
|||
shallowString = result.ToString(); |
|||
return true; |
|||
}); |
|||
return shallowString; |
|||
} |
|||
|
|||
public virtual string toStringDeep( |
|||
string prefixLineOne = "", |
|||
string prefixOtherLines = null, |
|||
DiagnosticLevel minLevel = DiagnosticLevel.debug |
|||
) { |
|||
return toDiagnosticsNode().toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines, minLevel: minLevel); |
|||
} |
|||
|
|||
public virtual string toStringShort() { |
|||
return foundation_.describeIdentity(this); |
|||
} |
|||
|
|||
public virtual DiagnosticsNode toDiagnosticsNode( |
|||
string name = null, |
|||
DiagnosticsTreeStyle style = DiagnosticsTreeStyle.sparse) { |
|||
return new DiagnosticableTreeNode( |
|||
name: name, |
|||
value: this, |
|||
style: style |
|||
); |
|||
} |
|||
|
|||
public virtual List<DiagnosticsNode> debugDescribeChildren() |
|||
{ |
|||
return new List<DiagnosticsNode>(); |
|||
} |
|||
|
|||
public virtual void debugFillProperties(DiagnosticPropertiesBuilder properties) { } |
|||
|
|||
|
|||
|
|||
} |
|||
{% endmacro %} |
|||
{{ DiagnosticableTreeMixin('ChangeNotifier') }} |
|||
} |
|||
|
|
|||
namespace Unity.UIWidgets.widgets { |
|||
{% macro DirectionalFocusTraversalPolicyMixin(with) %} |
|||
{% set className = 'DirectionalFocusTraversalPolicyMixin' + with %} |
|||
public class {{className}} : {{with}}, DirectionalFocusTraversalPolicyMixin { |
|||
protected {{className}}() { |
|||
} |
|||
|
|||
public readonly Dictionary<FocusScopeNode, _DirectionalPolicyData> _policyData = new Dictionary<FocusScopeNode, _DirectionalPolicyData>(); |
|||
public override void invalidateScopeData(FocusScopeNode node) { |
|||
base.invalidateScopeData(node); |
|||
_policyData.Remove(node); |
|||
} |
|||
public override void changedScope(FocusNode node = null, FocusScopeNode oldScope = null) { |
|||
base.changedScope(node: node, oldScope: oldScope); |
|||
if (oldScope != null) { |
|||
var delEntries = _policyData[oldScope]?.history?.Where((_DirectionalPolicyDataEntry entry)=> { |
|||
return entry.node == node; |
|||
}); |
|||
foreach (var delEntry in delEntries) { |
|||
_policyData[oldScope]?.history?.Remove(delEntry); |
|||
} |
|||
} |
|||
} |
|||
public override FocusNode findFirstFocusInDirection(FocusNode currentNode, TraversalDirection direction) { |
|||
D.assert(direction != null); |
|||
D.assert(currentNode != null); |
|||
switch (direction) { |
|||
case TraversalDirection.up: |
|||
return _sortAndFindInitial(currentNode, vertical: true, first: false); |
|||
case TraversalDirection.down: |
|||
return _sortAndFindInitial(currentNode, vertical: true, first: true); |
|||
case TraversalDirection.left: |
|||
return _sortAndFindInitial(currentNode, vertical: false, first: false); |
|||
case TraversalDirection.right: |
|||
return _sortAndFindInitial(currentNode, vertical: false, first: true); |
|||
} |
|||
return null; |
|||
} |
|||
public FocusNode _sortAndFindInitial(FocusNode currentNode, bool vertical = false, bool first = false) { |
|||
IEnumerable<FocusNode> nodes = currentNode.nearestScope.traversalDescendants; |
|||
List<FocusNode> sorted = nodes.ToList(); |
|||
FocusTravesalUtils.mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b)=> { |
|||
if (vertical) { |
|||
if (first) { |
|||
return a.rect.top.CompareTo(b.rect.top); |
|||
} else { |
|||
return b.rect.bottom.CompareTo(a.rect.bottom); |
|||
} |
|||
} else { |
|||
if (first) { |
|||
return a.rect.left.CompareTo(b.rect.left); |
|||
} else { |
|||
return b.rect.right.CompareTo(a.rect.right); |
|||
} |
|||
} |
|||
}); |
|||
if (sorted.isNotEmpty()) { |
|||
return sorted.First(); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public IEnumerable<FocusNode> _sortAndFilterHorizontally( |
|||
TraversalDirection direction, |
|||
Rect target, |
|||
FocusNode nearestScope) |
|||
{ |
|||
D.assert(direction == TraversalDirection.left || direction == TraversalDirection.right); |
|||
IEnumerable<FocusNode> nodes = nearestScope.traversalDescendants; |
|||
D.assert(!nodes.Contains(nearestScope)); |
|||
List<FocusNode> sorted = nodes.ToList(); |
|||
FocusTravesalUtils.mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b) => a.rect.center.dx.CompareTo(b.rect.center.dx)); |
|||
IEnumerable<FocusNode> result = new List<FocusNode>(); |
|||
switch (direction) { |
|||
case TraversalDirection.left: |
|||
result = sorted.Where((FocusNode node) => node.rect != target && node.rect.center.dx <= target.left); |
|||
break; |
|||
case TraversalDirection.right: |
|||
result = sorted.Where((FocusNode node) => node.rect != target && node.rect.center.dx >= target.right); |
|||
break; |
|||
case TraversalDirection.up: |
|||
case TraversalDirection.down: |
|||
break; |
|||
} |
|||
return result; |
|||
} |
|||
public IEnumerable<FocusNode> _sortAndFilterVertically( |
|||
TraversalDirection direction, |
|||
Rect target, |
|||
IEnumerable<FocusNode> nodes) |
|||
{ |
|||
List<FocusNode> sorted = nodes.ToList(); |
|||
FocusTravesalUtils.mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b) => a.rect.center.dy.CompareTo(b.rect.center.dy)); |
|||
switch (direction) { |
|||
case TraversalDirection.up: |
|||
return sorted.Where((FocusNode node) => node.rect != target && node.rect.center.dy <= target.top); |
|||
case TraversalDirection.down: |
|||
return sorted.Where((FocusNode node) => node.rect != target && node.rect.center.dy >= target.bottom); |
|||
case TraversalDirection.left: |
|||
case TraversalDirection.right: |
|||
break; |
|||
} |
|||
D.assert(direction == TraversalDirection.up || direction == TraversalDirection.down); |
|||
return null; |
|||
} |
|||
public bool _popPolicyDataIfNeeded(TraversalDirection direction, FocusScopeNode nearestScope, FocusNode focusedChild) { |
|||
_DirectionalPolicyData policyData = _policyData[nearestScope]; |
|||
if (policyData != null && policyData.history.isNotEmpty() && policyData.history.First().direction != direction) { |
|||
if (policyData.history.Last().node.parent == null) { |
|||
invalidateScopeData(nearestScope); |
|||
return false; |
|||
|
|||
} |
|||
bool popOrInvalidate(TraversalDirection direction) { |
|||
FocusNode lastNode = policyData.history.removeLast().node; |
|||
if (Scrollable.of(lastNode.context) != Scrollable.of(FocusManagerUtils.primaryFocus.context)) { |
|||
invalidateScopeData(nearestScope); |
|||
return false; |
|||
} |
|||
ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicitPolicy; |
|||
switch (direction) { |
|||
case TraversalDirection.up: |
|||
case TraversalDirection.left: |
|||
alignmentPolicy = ScrollPositionAlignmentPolicy.keepVisibleAtStart; |
|||
break; |
|||
case TraversalDirection.right: |
|||
case TraversalDirection.down: |
|||
alignmentPolicy = ScrollPositionAlignmentPolicy.keepVisibleAtEnd; |
|||
break; |
|||
} |
|||
FocusTravesalUtils._focusAndEnsureVisible( |
|||
lastNode, |
|||
alignmentPolicy: alignmentPolicy |
|||
); |
|||
return true; |
|||
} |
|||
switch (direction) { |
|||
case TraversalDirection.down: |
|||
case TraversalDirection.up: |
|||
switch (policyData.history.First().direction) { |
|||
case TraversalDirection.left: |
|||
case TraversalDirection.right: |
|||
invalidateScopeData(nearestScope); |
|||
break; |
|||
case TraversalDirection.up: |
|||
case TraversalDirection.down: |
|||
if (popOrInvalidate(direction)) { |
|||
return true; |
|||
} |
|||
break; |
|||
} |
|||
break; |
|||
case TraversalDirection.left: |
|||
case TraversalDirection.right: |
|||
switch (policyData.history.First().direction) { |
|||
case TraversalDirection.left: |
|||
case TraversalDirection.right: |
|||
if (popOrInvalidate(direction)) { |
|||
return true; |
|||
} |
|||
break; |
|||
case TraversalDirection.up: |
|||
case TraversalDirection.down: |
|||
invalidateScopeData(nearestScope); |
|||
break; |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
if (policyData != null && policyData.history.isEmpty()) { |
|||
invalidateScopeData(nearestScope); |
|||
} |
|||
return false; |
|||
|
|||
} |
|||
public void _pushPolicyData(TraversalDirection direction, FocusScopeNode nearestScope, FocusNode focusedChild) { |
|||
_DirectionalPolicyData policyData = _policyData[nearestScope]; |
|||
if (policyData != null && !(policyData is _DirectionalPolicyData)) { |
|||
return; |
|||
} |
|||
_DirectionalPolicyDataEntry newEntry = new _DirectionalPolicyDataEntry(node: focusedChild, direction: direction); |
|||
if (policyData != null) { |
|||
policyData.history.Add(newEntry); |
|||
} else { |
|||
_policyData[nearestScope] = new _DirectionalPolicyData(history: new List<_DirectionalPolicyDataEntry>(){newEntry}); |
|||
} |
|||
} |
|||
public override bool inDirection(FocusNode currentNode, TraversalDirection direction) { |
|||
FocusScopeNode nearestScope = currentNode.nearestScope; |
|||
FocusNode focusedChild = nearestScope.focusedChild; |
|||
if (focusedChild == null) { |
|||
FocusNode firstFocus = findFirstFocusInDirection(currentNode, direction) ?? currentNode; |
|||
switch (direction) { |
|||
case TraversalDirection.up: |
|||
case TraversalDirection.left: |
|||
FocusTravesalUtils._focusAndEnsureVisible( |
|||
firstFocus, |
|||
alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart |
|||
); |
|||
break; |
|||
case TraversalDirection.right: |
|||
case TraversalDirection.down: |
|||
FocusTravesalUtils._focusAndEnsureVisible( |
|||
firstFocus, |
|||
alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd |
|||
); |
|||
break; |
|||
} |
|||
return true; |
|||
} |
|||
if (_popPolicyDataIfNeeded(direction, nearestScope, focusedChild)) { |
|||
return true; |
|||
} |
|||
FocusNode found = null; |
|||
ScrollableState focusedScrollable = Scrollable.of(focusedChild.context); |
|||
switch (direction) { |
|||
case TraversalDirection.down: |
|||
case TraversalDirection.up: |
|||
IEnumerable<FocusNode> eligibleNodes = _sortAndFilterVertically( |
|||
direction, |
|||
focusedChild.rect, |
|||
nearestScope.traversalDescendants |
|||
); |
|||
if (focusedScrollable != null && !focusedScrollable.position.atEdge()) { |
|||
IEnumerable<FocusNode> filteredEligibleNodes = eligibleNodes.Where((FocusNode node) => Scrollable.of(node.context) == focusedScrollable); |
|||
if (filteredEligibleNodes.Count() !=0) { |
|||
eligibleNodes = filteredEligibleNodes; |
|||
} |
|||
} |
|||
if (eligibleNodes.Count() == 0) { |
|||
break; |
|||
} |
|||
List<FocusNode> sorted = eligibleNodes.ToList(); |
|||
if (direction == TraversalDirection.up) { |
|||
//sorted = sorted.reversed.toList(); |
|||
sorted.Reverse(); |
|||
sorted = sorted.ToList(); |
|||
} |
|||
Rect band = Rect.fromLTRB(focusedChild.rect.left, float.NegativeInfinity, focusedChild.rect.right, float.PositiveInfinity); |
|||
IEnumerable<FocusNode> inBand = sorted.Where((FocusNode node) => !node.rect.intersect(band).isEmpty); |
|||
if (inBand.Count() !=0) { |
|||
found = inBand.First(); |
|||
break; |
|||
} |
|||
FocusTravesalUtils.mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b)=> { |
|||
return (a.rect.center.dx - focusedChild.rect.center.dx).abs().CompareTo((b.rect.center.dx - focusedChild.rect.center.dx).abs()); |
|||
}); |
|||
found = sorted.First(); |
|||
break; |
|||
case TraversalDirection.right: |
|||
case TraversalDirection.left: |
|||
eligibleNodes = _sortAndFilterHorizontally(direction, focusedChild.rect, nearestScope); |
|||
if (focusedScrollable != null && !focusedScrollable.position.atEdge()) { |
|||
IEnumerable<FocusNode> filteredEligibleNodes = eligibleNodes.Where((FocusNode node) => Scrollable.of(node.context) == focusedScrollable); |
|||
if (filteredEligibleNodes.Count()!=0) { |
|||
eligibleNodes = filteredEligibleNodes; |
|||
} |
|||
} |
|||
if (eligibleNodes.Count() == 0) { |
|||
break; |
|||
} |
|||
sorted = eligibleNodes.ToList(); |
|||
if (direction == TraversalDirection.left) { |
|||
sorted.Reverse(); |
|||
sorted = sorted.ToList(); |
|||
//sorted = sorted.reversed.toList(); |
|||
} |
|||
band = Rect.fromLTRB(float.NegativeInfinity, focusedChild.rect.top, float.PositiveInfinity, focusedChild.rect.bottom); |
|||
inBand = sorted.Where((FocusNode node) => !node.rect.intersect(band).isEmpty); |
|||
if (inBand.Count()!=0) { |
|||
found = inBand.First(); |
|||
break; |
|||
} |
|||
FocusTravesalUtils.mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b) =>{ |
|||
return (a.rect.center.dy - focusedChild.rect.center.dy).abs().CompareTo((b.rect.center.dy - focusedChild.rect.center.dy).abs()); |
|||
}); |
|||
found = sorted.First(); |
|||
break; |
|||
} |
|||
if (found != null) { |
|||
_pushPolicyData(direction, nearestScope, focusedChild); |
|||
switch (direction) { |
|||
case TraversalDirection.up: |
|||
case TraversalDirection.left: |
|||
FocusTravesalUtils._focusAndEnsureVisible( |
|||
found, |
|||
alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart |
|||
); |
|||
break; |
|||
case TraversalDirection.down: |
|||
case TraversalDirection.right: |
|||
FocusTravesalUtils._focusAndEnsureVisible( |
|||
found, |
|||
alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd |
|||
); |
|||
break; |
|||
} |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
public override IEnumerable<FocusNode> sortDescendants(IEnumerable<FocusNode> descendants) { |
|||
return null; |
|||
} |
|||
|
|||
} |
|||
{% endmacro %} |
|||
{{ DirectionalFocusTraversalPolicyMixin('FocusTraversalPolicy') }} |
|||
} |
|||
|
撰写
预览
正在加载...
取消
保存
Reference in new issue