浏览代码

Merge pull request #43 from Unity-Technologies/shiyun/skia

Shiyun/skia
/siyaoH-1.17-PlatformMessage
GitHub 4 年前
当前提交
88187b12
共有 8 个文件被更改,包括 927 次插入44 次删除
  1. 40
      com.unity.uiwidgets/Runtime/cupertino/text_selection.cs
  2. 24
      com.unity.uiwidgets/Runtime/painting/binding.cs
  3. 4
      com.unity.uiwidgets/Runtime/widgets/banner.cs
  4. 2
      com.unity.uiwidgets/Runtime/widgets/basic.cs
  5. 480
      com.unity.uiwidgets/Runtime/widgets/focus_manager.cs
  6. 29
      com.unity.uiwidgets/Runtime/widgets/focus_scope.cs
  7. 13
      com.unity.uiwidgets/Runtime/widgets/text_selection.cs
  8. 379
      com.unity.uiwidgets/Runtime/widgets/focus_traversal.cs

40
com.unity.uiwidgets/Runtime/cupertino/text_selection.cs


}
class _CupertinoTextSelectionControls : TextSelectionControls {
public override Size getHandleSize(float textLineHeight) {
return new Size(
CupertinoTextSelectionUtils._kSelectionHandleRadius * 2,
textLineHeight + CupertinoTextSelectionUtils._kSelectionHandleRadius * 2 -
CupertinoTextSelectionUtils._kSelectionHandleOverlap
);
}
public override Widget buildToolbar(BuildContext context, Rect globalEditableRegion, Offset position,
public override Offset getHandleAnchor(TextSelectionHandleType type, float textLineHeight) {
Size handleSize = getHandleSize(textLineHeight);
switch (type) {
case TextSelectionHandleType.left:
return new Offset(
handleSize.width / 2,
handleSize.height
);
case TextSelectionHandleType.right:
return new Offset(
handleSize.width / 2,
handleSize.height - 2 * CupertinoTextSelectionUtils._kSelectionHandleRadius + CupertinoTextSelectionUtils._kSelectionHandleOverlap
);
default:
return new Offset(
handleSize.width / 2,
textLineHeight + (handleSize.height - textLineHeight) / 2
);
}
}
public override Widget buildToolbar(
BuildContext context,
Rect globalEditableRegion,
float textLineHeight,
Offset position,
List<TextSelectionPoint> endpoints,
TextSelectionDelegate del) {
D.assert(WidgetsD.debugCheckHasMediaQuery(context));
return new ConstrainedBox(

24
com.unity.uiwidgets/Runtime/painting/binding.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;

public ImageCache imageCache => _imageCache;
ImageCache _imageCache;
readonly _SystemFontsNotifier _systemFonts = new _SystemFontsNotifier();
public _SystemFontsNotifier systemFonts {
get { return _systemFonts; }
}
protected virtual ImageCache createImageCache() {
return new ImageCache();

public static partial class painting_ {
public static ImageCache imageCache => PaintingBinding.instance.imageCache;
}
public class _SystemFontsNotifier : Listenable {
HashSet<VoidCallback> _systemFontsCallbacks = new HashSet<VoidCallback>();
void notifyListeners () {
foreach (VoidCallback callback in _systemFontsCallbacks) {
callback();
}
}
public void addListener(VoidCallback listener) {
_systemFontsCallbacks.Add(listener);
}
public void removeListener(VoidCallback listener) {
_systemFontsCallbacks.Remove(listener);
}
}
}

4
com.unity.uiwidgets/Runtime/widgets/banner.cs


BannerLocation? location,
Color color = null,
TextStyle textStyle = null
) {
) : base (repaint: PaintingBinding.instance.systemFonts) {
D.assert(message != null);
D.assert(location != null);
this.color = color ?? BannerConstants._kColor;

base.debugFillProperties(properties);
properties.add(new StringProperty("message", message, showName: false));
properties.add(new EnumProperty<BannerLocation?>("location", location));
properties.add(new DiagnosticsProperty<Color>("color", color, showName: false));
properties.add(new ColorProperty("color", color, showName: false));
textStyle?.debugFillProperties(properties);
}
}

2
com.unity.uiwidgets/Runtime/widgets/basic.cs


}
public PointerExitEventListener getHandleExit() {
return widget.onExit == null ? null : handleExit;
return widget.onExit == null ? (PointerExitEventListener) null : handleExit;
}
public override Widget build(BuildContext context) {
return new _RawMouseRegion(this);

480
com.unity.uiwidgets/Runtime/widgets/focus_manager.cs


public static bool _focusDebug(string message, List<string> details = null) {
if (_kDebugFocus) {
//UnityEngine.Debug.Log();
UnityEngine.Debug.Log($"FOCUS: {message}");
if (details != null && details.Count() != 0) {
foreach (string detail in details) {

}
}
public class FocusNode : ChangeNotifier//DiagnosticableTreeMixin,
{
public class FocusNode : ChangeNotifier {
//DiagnosticableTreeMixin,
public FocusNode(
string debugLabel = "",
FocusOnKeyCallback onKey = null,

D.assert(canRequestFocus != null);
_skipTraversal = skipTraversal;
_canRequestFocus = canRequestFocus;
_onKey = onKey;
this.debugLabel = debugLabel;
/*_onKey = onKey {
this.debugLabel = debugLabel; ///????
}*/
}
public bool skipTraversal {

}
}
}
bool _skipTraversal;

get { return _context; }
}
BuildContext _context;
FocusOnKeyCallback onKey {

FocusOnKeyCallback _onKey;
public FocusManager _manager;

get { return _parent; }
}
public FocusNode _parent;

}
public readonly List<FocusNode> _children = new List<FocusNode>();
IEnumerable<FocusNode> traversalChildren {

}
return children.Where(
(FocusNode node) => !node.skipTraversal && node.canRequestFocus
);
List<FocusNode> nodes = new List<FocusNode>();
foreach (FocusNode node in children) {
if (!node.skipTraversal && node.canRequestFocus)
nodes.Add(node);
}
return nodes;
}
}

}
string _debugLabel;
IEnumerable<FocusNode> descendants {
public IEnumerable<FocusNode> descendants {
get {
if (_descendants == null) {
List<FocusNode> result = new List<FocusNode>();

}
IEnumerable<FocusNode> traversalDescendants {
public IEnumerable<FocusNode> traversalDescendants {
return descendants.Where((FocusNode node) => !node.skipTraversal && node.canRequestFocus);
List<FocusNode> nodes = new List<FocusNode>();
foreach (FocusNode node in descendants) {
if (!node.skipTraversal && node.canRequestFocus) {
nodes.Add(node);
}
}
// descendants.where((FocusNode node) => !node.skipTraversal && node.canRequestFocus);
return nodes;
}
}

/*bool nextFocus() {
return FocusTraversalGroup.of(context).next(this);
}
}*
bool previousFocus() {

}
public FocusScopeNode nearestScope {
get { return this; }
get { return enclosingScope; }
}
public bool isFirstFocus {

}
FocusNode focusedChild {
public FocusNode focusedChild {
get {
D.assert(_focusedChildren.isEmpty() || _focusedChildren.Last().enclosingScope == this,()=> "Focused child does not have the same idea of its enclosing scope as the scope does.");
return _focusedChildren.isNotEmpty() ? _focusedChildren.Last() : null;

}
public void autofocus(FocusNode node) {
D.assert(FocusManagerUtils._focusDebug($"Node autofocusing: {node}"));
D.assert(FocusManagerUtils._focusDebug("Node autofocusing: $node"));
if (focusedChild == null) {
if (node._parent == null) {
_reparent(node);

primaryFocus = scope.focusedChild;
}
if (primaryFocus == this) {
if (primaryFocus.canRequestFocus) {
_setAsFocusedChildForScope();
_markNextFocus(this);
}
if (primaryFocus.canRequestFocus) {
_setAsFocusedChildForScope();
_markNextFocus(this);
}
primaryFocus._doRequestFocus(findFirstFocus: findFirstFocus);
primaryFocus._doRequestFocus(findFirstFocus: findFirstFocus);
}
}

}
}
/*
public class FocusNode : ChangeNotifier {
internal FocusScopeNode _parent;
internal FocusManager _manager;
internal bool _hasKeyboardToken = false;
public bool hasFocus {
get {
FocusNode node = null;
if (_manager != null) {
node = _manager._currentFocus;
}
return node == this;
}
}
public bool consumeKeyboardToken() {
if (!_hasKeyboardToken) {
return false;
}
_hasKeyboardToken = false;
return true;
}
public void unfocus() {
if (_parent != null) {
_parent._resignFocus(this);
}
D.assert(_parent == null);
D.assert(_manager == null);
}
public override void dispose() {
if (_manager != null) {
_manager._willDisposeFocusNode(this);
}
if (_parent != null) {
_parent._resignFocus(this);
}
D.assert(_parent == null);
D.assert(_manager == null);
base.dispose();
}
internal void _notify() {
notifyListeners();
}
public override string ToString() {
return $"{foundation_.describeIdentity(this)} hasFocus: {hasFocus}";
}
}
public class FocusScopeNode : DiagnosticableTree {
internal FocusManager _manager;
internal FocusScopeNode _parent;
internal FocusScopeNode _nextSibling;
internal FocusScopeNode _previousSibling;
internal FocusScopeNode _firstChild;
internal FocusScopeNode _lastChild;
internal FocusNode _focus;
internal List<FocusScopeNode> _focusPath;
public bool isFirstFocus {
get { return _parent == null || _parent._firstChild == this; }
}
internal List<FocusScopeNode> _getFocusPath() {
List<FocusScopeNode> nodes = new List<FocusScopeNode> {this};
FocusScopeNode node = _parent;
while (node != null && node != _manager?.rootScope) {
nodes.Add(node);
node = node._parent;
}
return nodes;
}
internal void _prepend(FocusScopeNode child) {
D.assert(child != this);
D.assert(child != _firstChild);
D.assert(child != _lastChild);
D.assert(child._parent == null);
D.assert(child._manager == null);
D.assert(child._nextSibling == null);
D.assert(child._previousSibling == null);
D.assert(() => {
var node = this;
while (node._parent != null) {
node = node._parent;
}
D.assert(node != child);
return true;
});
child._parent = this;
child._nextSibling = _firstChild;
if (_firstChild != null) {
_firstChild._previousSibling = child;
}
_firstChild = child;
_lastChild = _lastChild ?? child;
child._updateManager(_manager);
}
void _updateManager(FocusManager manager) {
Action<FocusScopeNode> update = null;
update = (child) => {
if (child._manager == manager) {
return;
}
child._manager = manager;
// We don"t proactively null out the manager for FocusNodes because the
// manager holds the currently active focus node until the end of the
// microtask, even if that node is detached from the focus tree.
if (manager != null && child._focus != null) {
child._focus._manager = manager;
}
child._visitChildren(update);
};
update(this);
}
void _visitChildren(Action<FocusScopeNode> vistor) {
FocusScopeNode child = _firstChild;
while (child != null) {
vistor.Invoke(child);
child = child._nextSibling;
}
}
bool _debugUltimatePreviousSiblingOf(FocusScopeNode child, FocusScopeNode equals) {
while (child._previousSibling != null) {
D.assert(child._previousSibling != child);
child = child._previousSibling;
}
return child == equals;
}
bool _debugUltimateNextSiblingOf(FocusScopeNode child, FocusScopeNode equals) {
while (child._nextSibling != null) {
D.assert(child._nextSibling != child);
child = child._nextSibling;
}
return child == equals;
}
internal void _remove(FocusScopeNode child) {
D.assert(child._parent == this);
D.assert(child._manager == _manager);
D.assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
D.assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
if (child._previousSibling == null) {
D.assert(_firstChild == child);
_firstChild = child._nextSibling;
}
else {
child._previousSibling._nextSibling = child._nextSibling;
}
if (child._nextSibling == null) {
D.assert(_lastChild == child);
_lastChild = child._previousSibling;
}
else {
child._nextSibling._previousSibling = child._previousSibling;
}
child._previousSibling = null;
child._nextSibling = null;
child._parent = null;
child._updateManager(null);
}
internal void _didChangeFocusChain() {
if (isFirstFocus && _manager != null) {
_manager._markNeedsUpdate();
}
}
// TODO: need update
public void requestFocus(FocusNode node = null) {
// D.assert(node != null);
var focusPath = _manager?._getCurrentFocusPath();
if (_focus == node &&
(_focusPath == focusPath || (focusPath != null && _focusPath != null &&
_focusPath.SequenceEqual(focusPath)))) {
return;
}
if (_focus != null) {
_focus.unfocus();
}
node._hasKeyboardToken = true;
_setFocus(node);
}
public void autofocus(FocusNode node) {
D.assert(node != null);
if (_focus == null) {
node._hasKeyboardToken = true;
_setFocus(node);
}
}
public void reparentIfNeeded(FocusNode node) {
D.assert(node != null);
if (node._parent == null || node._parent == this) {
return;
}
node.unfocus();
D.assert(node._parent == null);
if (_focus == null) {
_setFocus(node);
}
}
internal void _setFocus(FocusNode node) {
D.assert(node != null);
D.assert(node._parent == null);
D.assert(_focus == null);
_focus = node;
_focus._parent = this;
_focus._manager = _manager;
_focus._hasKeyboardToken = true;
_didChangeFocusChain();
_focusPath = _getFocusPath();
}
internal void _resignFocus(FocusNode node) {
D.assert(node != null);
if (_focus != node) {
return;
}
_focus._parent = null;
_focus._manager = null;
_focus = null;
_didChangeFocusChain();
}
public void setFirstFocus(FocusScopeNode child) {
D.assert(child != null);
D.assert(child._parent == null || child._parent == this);
if (_firstChild == child) {
return;
}
child.detach();
_prepend(child);
D.assert(child._parent == this);
_didChangeFocusChain();
}
public void reparentScopeIfNeeded(FocusScopeNode child) {
D.assert(child != null);
if (child._parent == null || child._parent == this) {
return;
}
if (child.isFirstFocus) {
setFirstFocus(child);
}
else {
child.detach();
}
}
public void detach() {
_didChangeFocusChain();
if (_parent != null) {
_parent._remove(this);
}
D.assert(_parent == null);
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
if (_focus != null) {
properties.add(new DiagnosticsProperty<FocusNode>("focus", _focus));
}
}
public override List<DiagnosticsNode> debugDescribeChildren() {
var children = new List<DiagnosticsNode>();
if (_firstChild != null) {
FocusScopeNode child = _firstChild;
int count = 1;
while (true) {
children.Add(child.toDiagnosticsNode(name: $"child {count}"));
if (child == _lastChild) {
break;
}
child = child._nextSibling;
count += 1;
}
}
return children;
}
}
public class FocusManager {
public FocusManager() {
rootScope._manager = this;
D.assert(rootScope._firstChild == null);
D.assert(rootScope._lastChild == null);
}
public readonly FocusScopeNode rootScope = new FocusScopeNode();
internal readonly FocusScopeNode _noneScope = new FocusScopeNode();
public FocusNode currentFocus {
get { return _currentFocus; }
}
internal FocusNode _currentFocus;
internal void _willDisposeFocusNode(FocusNode node) {
D.assert(node != null);
if (_currentFocus == node) {
_currentFocus = null;
}
}
bool _haveScheduledUpdate = false;
internal void _markNeedsUpdate() {
if (_haveScheduledUpdate) {
return;
}
_haveScheduledUpdate = true;
async_.scheduleMicrotask(() => {
_update();
return null;
});
}
internal FocusNode _findNextFocus() {
FocusScopeNode scope = rootScope;
while (scope._firstChild != null) {
scope = scope._firstChild;
}
return scope._focus;
}
internal void _update() {
_haveScheduledUpdate = false;
var nextFocus = _findNextFocus();
if (_currentFocus == nextFocus) {
return;
}
var previousFocus = _currentFocus;
_currentFocus = nextFocus;
if (previousFocus != null) {
previousFocus._notify();
}
if (_currentFocus != null) {
_currentFocus._notify();
}
}
internal List<FocusScopeNode> _getCurrentFocusPath() {
return _currentFocus?._parent?._getFocusPath();
}
public void focusNone(bool focus) {
if (focus) {
if (_noneScope._parent != null && _noneScope.isFirstFocus) {
return;
}
rootScope.setFirstFocus(_noneScope);
}
else {
if (_noneScope._parent == null) {
return;
}
_noneScope.detach();
}
}
public override string ToString() {
var status = _haveScheduledUpdate ? " UPDATE SCHEDULED" : "";
var indent = " ";
return string.Format("{1}{2}\n{0}currentFocus: {3}\n{4}", indent, foundation_.describeIdentity(this),
status, _currentFocus,
rootScope.toStringDeep(prefixLineOne: indent, prefixOtherLines: indent));
}
}*/

29
com.unity.uiwidgets/Runtime/widgets/focus_scope.cs


bool? skipTraversal = null,
FocusOnKeyCallback onKey = null,
string debugLabel = null
) : base(
key: key,
child: child,
focusNode: node,
autofocus: autofocus,
onFocusChange: onFocusChange,
canRequestFocus: canRequestFocus,
skipTraversal: skipTraversal,
onKey: onKey,
debugLabel: debugLabel) {
) : base(
key: key,
child: child,
focusNode: node,
autofocus: autofocus,
onFocusChange: onFocusChange,
canRequestFocus: canRequestFocus,
skipTraversal: skipTraversal,
onKey: onKey,
debugLabel: debugLabel) {
public static FocusScopeNode of(BuildContext context) {
D.assert(context != null);
_FocusMarker marker = context.dependOnInheritedWidgetOfExactType<_FocusMarker>();

public class _FocusState : State<Focus> {
FocusNode _internalNode;
public FocusNode focusNode {
get {
return widget.focusNode ?? _internalNode;

base.didUpdateWidget(oldWidget);
D.assert(()=> {
if (((Focus)oldWidget).debugLabel != widget.debugLabel && _internalNode != null) {
_internalNode.debugLabel = widget.debugLabel;
}
return true;
_internalNode.debugLabel = widget.debugLabel;
}
return true;
});
if (((Focus)oldWidget).focusNode == widget.focusNode) {

}
}

13
com.unity.uiwidgets/Runtime/widgets/text_selection.cs


}
bool canCopy(TextSelectionDelegate _delegate) {
public bool canCopy(TextSelectionDelegate _delegate) {
bool canPaste(TextSelectionDelegate _delegate) {
public bool canPaste(TextSelectionDelegate _delegate) {
bool canSelectAll(TextSelectionDelegate _delegate) {
public bool canSelectAll(TextSelectionDelegate _delegate) {
return _delegate.selectAllEnabled
&& _delegate.textEditingValue.text.isNotEmpty()
&& _delegate.textEditingValue.selection.isCollapsed;

link: layerLink,
showWhenUnlinked: false,
offset: -editingRegion.topLeft,
child: selectionControls.buildToolbar(context, editingRegion, midpoint, selectionDelegate)
child: selectionControls.buildToolbar(context,
editingRegion,
renderObject.preferredLineHeight,
midpoint,
endpoints,
selectionDelegate)
)
);
}

379
com.unity.uiwidgets/Runtime/widgets/focus_traversal.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
namespace Unity.UIWidgets.widgets {
/*public class FocusTraversalGroup : StatefulWidget {
public FocusTraversalGroup(
Key key = null,
FocusTraversalPolicy policy = null,
Widget child = null
) : base(key: key) {
policy = policy ?? new ReadingOrderTraversalPolicy();
this.child = child;
}
public readonly Widget child;
public readonly FocusTraversalPolicy policy;
public static FocusTraversalPolicy of(BuildContext context, bool nullOk = false) {
D.assert(context != null);
_FocusTraversalGroupMarker inherited = context?.dependOnInheritedWidgetOfExactType<_FocusTraversalGroupMarker>();
D.assert(() =>{
if (nullOk) {
return true;
}
if (inherited == null) {
throw new UIWidgetsError(
"Unable to find a FocusTraversalGroup widget in the context.\n" +
"FocusTraversalGroup.of() was called with a context that does not contain a " +
"FocusTraversalGroup.\n" +
"No FocusTraversalGroup ancestor could be found starting from the context that was " +
"passed to FocusTraversalGroup.of(). This can happen because there is not a " +
"WidgetsApp or MaterialApp widget (those widgets introduce a FocusTraversalGroup), " +
"or it can happen if the context comes from a widget above those widgets.\n" +
"The context used was:\n" +
$" {context}"
);
}
return true;
});
return inherited?.policy;
}
public override State createState() {
return new _FocusTraversalGroupState();
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new TextTreeRenderer.DiagnosticsProperty<FocusTraversalPolicy>("policy", policy));
}
}
public class _FocusTraversalGroupState : State<FocusTraversalGroup> {
FocusNode focusNode;
public override void initState() {
base.initState();
focusNode = new FocusNode(
canRequestFocus: false,
skipTraversal: true,
debugLabel: "FocusTraversalGroup"
);
}
public override void dispose() {
focusNode?.dispose();
base.dispose();
}
public override Widget build(BuildContext context) {
return new _FocusTraversalGroupMarker(
policy: widget.policy,
focusNode: focusNode,
child: new Focus(
focusNode: focusNode,
canRequestFocus: false,
skipTraversal: true,
includeSemantics: false,
child: widget.child
)
);
}
}
public class _FocusTraversalGroupMarker : InheritedWidget {
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 readonly FocusTraversalPolicy policy;
public readonly FocusNode focusNode;
public override bool updateShouldNotify(InheritedWidget oldWidget) => false;
}
public abstract class FocusTraversalPolicy : TextTreeRenderer.Diagnosticable {
public FocusTraversalPolicy() {
}
public virtual FocusNode findFirstFocus(FocusNode currentNode) {
D.assert(currentNode != null);
FocusScopeNode scope = currentNode.nearestScope;
FocusNode candidate = scope.focusedChild;
if (candidate == null && scope.descendants.Count() != 0) {
List<FocusNode> sorted = _sortAllDescendants(scope);
candidate = sorted.isNotEmpty() ? sorted.First() : null;
}
candidate ??= currentNode;
return candidate;
}
public abstract FocusNode findFirstFocusInDirection(FocusNode currentNode, TraversalDirection direction);
public abstract void invalidateScopeData(FocusScopeNode node);
public abstract void changedScope(FocusNode node = null, FocusScopeNode oldScope = null);
bool next(FocusNode currentNode) => _moveFocus(currentNode, forward: true);
bool previous(FocusNode currentNode) => _moveFocus(currentNode, forward: false);
public abstract bool inDirection(FocusNode currentNode, TraversalDirection direction);
public abstract IEnumerable<FocusNode> sortDescendants(IEnumerable<FocusNode> descendants);
public _FocusTraversalGroupMarker _getMarker(BuildContext context) {
return context?.getElementForInheritedWidgetOfExactType<_FocusTraversalGroupMarker>()?.widget as _FocusTraversalGroupMarker;
}
public List<FocusNode> _sortAllDescendants(FocusScopeNode scope) {
D.assert(scope != null);
_FocusTraversalGroupMarker scopeGroupMarker = _getMarker(scope.context);
FocusTraversalPolicy defaultPolicy = scopeGroupMarker?.policy ?? 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 = _getAncestor(groupNode.context, count: 2);
_FocusTraversalGroupMarker parentMarker = _getMarker(parentContext);
FocusNode parentNode = parentMarker?.focusNode;
groups[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] ??= _FocusTraversalGroupInfo(groupMarker, members: new List<FocusNode>(), defaultPolicy: defaultPolicy);
D.assert(!groups[groupNode].members.contains(node));
groups[groupNode].members.add(node);
}
}
HashSet<FocusNode> groupKeys = groups.Keys.ToSet();
foreach ( FocusNode key in groups.keys) {
List<FocusNode> sortedMembers = groups[key].policy.sortDescendants(groups[key].members).toList();
groups[key].members.clear();
groups[key].members.addAll(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(
sortedDescendants.toSet().difference(scope.traversalDescendants.toSet()).isEmpty,
$"sorted descendants contains more nodes than it should: ({sortedDescendants.toSet().difference(scope.traversalDescendants.toSet())})"
);
D.assert(
scope.traversalDescendants.toSet().difference(sortedDescendants.toSet()).isEmpty,
"sorted descendants are missing some nodes: (${scope.traversalDescendants.toSet().difference(sortedDescendants.toSet())})"
);
return sortedDescendants;
}
protected bool _moveFocus(FocusNode currentNode, bool forward = false) {
D.assert(forward != null);
if (currentNode == null) {
return false;
}
FocusScopeNode nearestScope = currentNode.nearestScope;
invalidateScopeData(nearestScope);
FocusNode focusedChild = nearestScope.focusedChild;
if (focusedChild == null) {
FocusNode firstFocus = findFirstFocus(currentNode);
if (firstFocus != null) {
_focusAndEnsureVisible(
firstFocus,
alignmentPolicy: forward ? ScrollPositionAlignmentPolicy.keepVisibleAtEnd : ScrollPositionAlignmentPolicy.keepVisibleAtStart,
);
return true;
}
}
List<FocusNode> sortedNodes = _sortAllDescendants(nearestScope);
if (forward && focusedChild == sortedNodes.Last()) {
_focusAndEnsureVisible(sortedNodes.First(), alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd);
return true;
}
if (!forward && focusedChild == sortedNodes.First()) {
_focusAndEnsureVisible(sortedNodes.Last(), alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart);
return true;
}
IEnumerable<FocusNode> maybeFlipped = new List<FocusNode>();
if (forward) {
maybeFlipped = sortedNodes;
}
else {
sortedNodes.Reverse();
maybeFlipped = sortedNodes;
}
FocusNode previousNode = null;
foreach ( FocusNode node in maybeFlipped) {
if (previousNode == focusedChild) {
_focusAndEnsureVisible(
node,
alignmentPolicy: forward ? ScrollPositionAlignmentPolicy.keepVisibleAtEnd : ScrollPositionAlignmentPolicy.keepVisibleAtStart,
);
return true;
}
previousNode = node;
}
return false;
}
}
public class _DirectionalPolicyDataEntry {
public _DirectionalPolicyDataEntry(
TraversalDirection direction ,
FocusNode node ) {
this.direction = direction;
this.node = node;
}
public readonly TraversalDirection direction;
public readonly FocusNode node;
}
class _ReadingOrderDirectionalGroupData : Diagnosticable {
public _ReadingOrderDirectionalGroupData(List<_ReadingOrderSortData> members) {
this.members = members;
}
public readonly List<_ReadingOrderSortData> members;
TextDirection directionality {
get {
return members.First().directionality;
}
}
Rect _rect;
Rect rect {
get {if (_rect == null) {
foreach(Rect rect in members.Select<Rect>(
(_ReadingOrderSortData data) => data.rect)){
_rect ??= rect;
_rect = _rect.expandToInclude(rect);
}
}
return _rect;
}
}
List<Directionality> memberAncestors {
get { if (_memberAncestors == null) {
_memberAncestors = new List<Directionality>();
foreach (_ReadingOrderSortData member in members) {
_memberAncestors.AddRange(member.directionalAncestors);
}
}
return _memberAncestors; }
}
List<Directionality> _memberAncestors;
public static void sortWithDirectionality(List<_ReadingOrderDirectionalGroupData> list, TextDirection directionality) {
mergeSort<_ReadingOrderDirectionalGroupData>(list, compare: (_ReadingOrderDirectionalGroupData a, _ReadingOrderDirectionalGroupData b) =>{
switch (directionality) {
case TextDirection.ltr:
return a.rect.left.compareTo(b.rect.left);
case TextDirection.rtl:
return b.rect.right.compareTo(a.rect.right);
}
D.assert(false, ()=>"Unhandled directionality $directionality");
return 0;
});
}
public override void debugFillProperties(TextTreeRenderer.DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(DiagnosticsProperty<TextDirection>("directionality", directionality));
properties.add(DiagnosticsProperty<Rect>("rect", rect));
properties.add(IterableProperty<String>("members", members.map<String>((_ReadingOrderSortData member) {
return ""${member.node.debugLabel}"(${member.rect})";
})));
}
}
public class ReadingOrderTraversalPolicy : FocusTraversalPolicy , DirectionalFocusTraversalPolicyMixin {
public List<_ReadingOrderDirectionalGroupData> _collectDirectionalityGroups(IEnumerable<_ReadingOrderSortData> candidates) {
TextDirection currentDirection = candidates.First().directionality;
List<_ReadingOrderSortData> currentGroup = new List<_ReadingOrderSortData>();
List<_ReadingOrderDirectionalGroupData> result = new List<_ReadingOrderDirectionalGroupData>();
foreach ( _ReadingOrderSortData candidate in candidates) {
if (candidate.directionality == currentDirection) {
currentGroup.Add(candidate);
continue;
}
currentDirection = candidate.directionality;
result.Add(_ReadingOrderDirectionalGroupData(currentGroup));
currentGroup = new List<_ReadingOrderSortData>(){candidate};
}
if (currentGroup.isNotEmpty()) {
result.Add(_ReadingOrderDirectionalGroupData(currentGroup));
}
foreach ( _ReadingOrderDirectionalGroupData bandGroup in result) {
if (bandGroup.members.length == 1) {
continue;
}
_ReadingOrderSortData.sortWithDirectionality(bandGroup.members, bandGroup.directionality);
}
return result;
}
public _ReadingOrderSortData _pickNext(List<_ReadingOrderSortData> candidates) {
mergeSort<_ReadingOrderSortData>(candidates, compare: (_ReadingOrderSortData a, _ReadingOrderSortData b) => a.rect.top.compareTo(b.rect.top));
_ReadingOrderSortData topmost = candidates.First();
List<_ReadingOrderSortData> inBand(_ReadingOrderSortData current, IEnumerable<_ReadingOrderSortData> candidates) {
Rect band = Rect.fromLTRB(double.negativeInfinity, current.rect.top, double.infinity, current.rect.bottom);
return candidates.Where((_ReadingOrderSortData item)=> {
return !item.rect.intersect(band).isEmpty;
}).ToList();
}
List<_ReadingOrderSortData> inBandOfTop = inBand(topmost, candidates);
D.assert(topmost.rect.isEmpty || inBandOfTop.isNotEmpty);
if (inBandOfTop.Count <= 1) {
return topmost;
}
TextDirection nearestCommonDirectionality = _ReadingOrderSortData.commonDirectionalityOf(inBandOfTop);
_ReadingOrderSortData.sortWithDirectionality(inBandOfTop, nearestCommonDirectionality);
List<_ReadingOrderDirectionalGroupData> bandGroups = _collectDirectionalityGroups(inBandOfTop);
if (bandGroups.Count == 1) {
return bandGroups.First().members.first;
}
_ReadingOrderDirectionalGroupData.sortWithDirectionality(bandGroups, nearestCommonDirectionality);
return bandGroups.First().members.first;
}
public override IEnumerable<FocusNode> sortDescendants(IEnumerable<FocusNode> descendants) {
D.assert(descendants != null);
if (descendants.Count() <= 1) {
return descendants;
}
List<_ReadingOrderSortData> data = new List<_ReadingOrderSortData>(){
foreach ( FocusNode node in descendants)
_ReadingOrderSortData(node),
};
List<FocusNode> sortedList = new List<FocusNode>();
List<_ReadingOrderSortData> unplaced = data;
_ReadingOrderSortData current = _pickNext(unplaced);
sortedList.Add(current.node);
unplaced.Remove(current);
while (unplaced.isNotEmpty()) {
_ReadingOrderSortData next = _pickNext(unplaced);
current = next;
sortedList.Add(current.node);
unplaced.Remove(current);
}
return sortedList;
}
}*/
}
正在加载...
取消
保存