// Note that this is overridden in FocusScopeNode.
        public virtual void _doRequestFocus(bool findFirstFocus = false)
        {
            D.assert(findFirstFocus != null);
            if (!canRequestFocus)
            {
                D.assert(FocusManagerUtils._focusDebug(
                             $"Node NOT requesting focus because canRequestFocus is false: {this}"));
                return;
            }

            if (_parent == null)
            {
                _requestFocusWhenReparented = true;
                return;
            }

            _setAsFocusedChildForScope();
            if (hasPrimaryFocus && (_manager._markedForFocus == null || _manager._markedForFocus == this))
            {
                return;
            }

            _hasKeyboardToken = true;
            D.assert(FocusManagerUtils._focusDebug($"Node requesting focus: {this}"));
            _markNextFocus(this);
        }
        public void unfocus(
            UnfocusDisposition disposition = UnfocusDisposition.scope
            )
        {
            D.assert(disposition != null);
            if (!hasFocus && (_manager == null || _manager._markedForFocus != this))
            {
                return;
            }

            FocusScopeNode scope = enclosingScope;

            if (scope == null)
            {
                return;
            }

            switch (disposition)
            {
            case UnfocusDisposition.scope:
                if (scope.canRequestFocus)
                {
                    scope._focusedChildren.Clear();
                }

                while (!scope.canRequestFocus)
                {
                    scope = scope.enclosingScope ?? _manager?.rootScope;
                }

                scope?._doRequestFocus(findFirstFocus: false);
                break;

            case UnfocusDisposition.previouslyFocusedChild:

                if (scope.canRequestFocus)
                {
                    scope?._focusedChildren?.Remove(this);
                }

                while (!scope.canRequestFocus)
                {
                    scope.enclosingScope?._focusedChildren?.Remove(scope);
                    scope = scope.enclosingScope ?? _manager?.rootScope;
                }

                scope?._doRequestFocus(findFirstFocus: true);
                break;
            }

            D.assert(FocusManagerUtils._focusDebug("Unfocused node:",
                                                   new List <string> {
                $"primary focus was {this}", $"next focus will be {_manager?._markedForFocus}"
            }));
        }
        public void _setAsFocusedChildForScope()
        {
            FocusNode scopeFocus = this;

            foreach (var ancestor in ancestors)
            {
                if (ancestor is FocusScopeNode)
                {
                    D.assert(scopeFocus != ancestor, () => "Somehow made a loop by setting focusedChild to its scope.");
                    D.assert(FocusManagerUtils._focusDebug($"Setting {scopeFocus} as focused child for scope:",
                                                           new List <string> {
                        ancestor.ToString()
                    }));
                    ((FocusScopeNode)ancestor)._focusedChildren.Remove(scopeFocus);

                    ((FocusScopeNode)ancestor)._focusedChildren.Add(scopeFocus);
                    scopeFocus = ancestor;
                }
            }
        }
        public void detach()
        {
            D.assert(_node != null);
            D.assert(FocusManagerUtils._focusDebug("Detaching node:", new List <string> {
                _node.ToString(), $"With enclosing scope {_node.enclosingScope}"
            }));
            if (isAttached)
            {
                if (_node.hasPrimaryFocus || (_node._manager != null && _node._manager._markedForFocus == _node))
                {
                    _node.unfocus(disposition: UnfocusDisposition.previouslyFocusedChild);
                }

                _node._manager?._markDetached(_node);
                _node._parent?._removeChild(_node);
                _node._attachment = null;
                D.assert(!_node.hasPrimaryFocus);
                D.assert(_node._manager?._markedForFocus != _node);
            }
            D.assert(!isAttached);
        }