fzhangtj
6 年前
当前提交
f6a39c1b
共有 7 个文件被更改,包括 475 次插入 和 8 次删除
-
2Assets/UIWidgets/foundation/diagnostics.cs
-
3Assets/UIWidgets/widgets/binding.cs
-
389Assets/UIWidgets/widgets/focus_manager.cs
-
4Assets/UIWidgets/widgets/focus_manager.cs.meta
-
5Assets/UIWidgets/widgets/framework.cs
-
77Assets/UIWidgets/widgets/focus_scope.cs
-
3Assets/UIWidgets/widgets/focus_scope.cs.meta
|
|||
namespace UIWidgets.widgets { |
|||
public class FocusManager { |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.widgets |
|||
{ |
|||
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 string.Format("{0} hasFocus: {1}", Diagnostics.describeIdentity(this), 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; |
|||
|
|||
public bool isFirstFocus |
|||
{ |
|||
get { return _parent == null || _parent._firstChild == this; } |
|||
} |
|||
|
|||
internal void _prepend(FocusScopeNode child) |
|||
{ |
|||
D.assert(child != this); |
|||
D.assert(child != _firstChild); |
|||
D.assert(child != _lastChild); |
|||
D.assert(child == 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; |
|||
} |
|||
} |
|||
|
|||
private bool _debugUltimatePreviousSiblingOf(FocusScopeNode child, FocusScopeNode equals) |
|||
{ |
|||
while (child._previousSibling != null) |
|||
{ |
|||
D.assert(child._previousSibling != child); |
|||
child = child._previousSibling; |
|||
} |
|||
|
|||
return child == equals; |
|||
} |
|||
|
|||
private 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(); |
|||
} |
|||
|
|||
public void requestFocus(FocusNode node) |
|||
{ |
|||
D.assert(node != null); |
|||
if (_focus == node) |
|||
{ |
|||
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(); |
|||
} |
|||
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: string.Format("child {0}", count))); |
|||
if (child == _lastChild) |
|||
break; |
|||
child = child._nextSibling; |
|||
count += 1; |
|||
} |
|||
} |
|||
return children; |
|||
} |
|||
} |
|||
|
|||
public class FocusManager |
|||
{ |
|||
public FocusManager(Window window) |
|||
{ |
|||
rootScope._manager = this; |
|||
this.window = window; |
|||
D.assert(rootScope._firstChild == null); |
|||
D.assert(rootScope._lastChild == null); |
|||
} |
|||
|
|||
public readonly Window window; |
|||
public readonly FocusScopeNode rootScope = new FocusScopeNode(); |
|||
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; |
|||
window.scheduleMicrotask(_update); |
|||
} |
|||
|
|||
|
|||
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(); |
|||
} |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
var status = _haveScheduledUpdate ? " UPDATE SCHEDULED" : ""; |
|||
var indent = " "; |
|||
return string.Format("{1}{2}\n{0}currentFocus: {3}\n{4}", indent, Diagnostics.describeIdentity(this), |
|||
status, _currentFocus, rootScope.toStringDeep(prefixLineOne: indent, prefixOtherLines: indent)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 78895a8736b34e4085f9324116273d59 |
|||
timeCreated: 1536819300 |
|||
guid: f645f061c05e472285a90ddf48ebeeed |
|||
timeCreated: 1536895704 |
|
|||
using UIWidgets.foundation; |
|||
|
|||
namespace UIWidgets.widgets |
|||
{ |
|||
|
|||
class _FocusScopeMarker: InheritedWidget { |
|||
|
|||
public _FocusScopeMarker( FocusScopeNode node, Widget child, Key key = null) : base(key, child) |
|||
{ |
|||
D.assert(node != null); |
|||
this.node = node; |
|||
} |
|||
|
|||
public readonly FocusScopeNode node; |
|||
|
|||
public override bool updateShouldNotify(InheritedWidget oldWidget) |
|||
{ |
|||
return node != ((_FocusScopeMarker)oldWidget).node; |
|||
} |
|||
} |
|||
|
|||
public class FocusScope : StatefulWidget |
|||
{ |
|||
public FocusScope(FocusScopeNode node, Widget child, Key key = null, bool autofocus = false) : base(key) |
|||
{ |
|||
this.node = node; |
|||
this.child = child; |
|||
this.autofocus = autofocus; |
|||
} |
|||
|
|||
public readonly FocusScopeNode node; |
|||
|
|||
public readonly bool autofocus; |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public static FocusScopeNode of(BuildContext context) { |
|||
var scope = (_FocusScopeMarker)context.inheritFromWidgetOfExactType(typeof(_FocusScopeMarker)); |
|||
if (scope != null && scope.node != null) |
|||
{ |
|||
return scope.node; |
|||
} |
|||
return context.owner.focusManager.rootScope; |
|||
} |
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _FocusScopeState(); |
|||
} |
|||
} |
|||
|
|||
class _FocusScopeState : State<FocusScope> |
|||
{ |
|||
private bool _didAutofocus = false; |
|||
|
|||
public override void didChangeDependencies() |
|||
{ |
|||
base.didChangeDependencies(); |
|||
if (!_didAutofocus && widget.autofocus) |
|||
{ |
|||
FocusScope.of(context).setFirstFocus(widget.node); |
|||
_didAutofocus = true; |
|||
} |
|||
} |
|||
|
|||
public override void dispose() { |
|||
widget.node.detach(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
FocusScope.of(context).reparentScopeIfNeeded(widget.node); |
|||
return new _FocusScopeMarker(node:widget.node, child:widget.child); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: c5976c3bfa824d30a0fba367accca614 |
|||
timeCreated: 1536895629 |
撰写
预览
正在加载...
取消
保存
Reference in new issue