internal static object?FindNextFocusWithSearchRootIgnoreEngagementWithHintRectImpl(
            FocusNavigationDirection focusNavigationDirection,
            object pSearchRoot,
            Rect focusHintRectangle,
            Rect focusExclusionRectangle)
        {
            object?          spScope   = pSearchRoot;
            DependencyObject?spScopeDO = spScope as DependencyObject;

            object?candidate = null;

            Rect hintRect = focusHintRectangle;
            Rect exRect   = focusExclusionRectangle;

            var cDOSearchRoot = spScopeDO;

            if (cDOSearchRoot == null && InIslandsMode())
            {
                // Return error if cDOSearchRoot is not valid in islands/ desktop mode
                throw new InvalidOperationException("Search root is invalid.");
            }

            XYFocusOptions xyFocusOptions = new XYFocusOptions();

            xyFocusOptions.SearchRoot         = cDOSearchRoot;
            xyFocusOptions.ConsiderEngagement = false;
            xyFocusOptions.FocusHintRectangle = hintRect;
            xyFocusOptions.ExclusionRect      = exRect;

            candidate = FindNextFocus(focusNavigationDirection, xyFocusOptions);
            return(candidate);
        }
        internal static object?FindNextFocusWithSearchRootIgnoreEngagementWithClipImpl(
            FocusNavigationDirection focusNavigationDirection,
            object pSearchRoot,
            bool ignoreClipping,
            bool ignoreCone)
        {
            object?          spScope   = pSearchRoot;
            DependencyObject?spScopeDO = spScope as DependencyObject;

            object?candidate = null;

            var cDOSearchRoot = spScopeDO as DependencyObject;

            if (cDOSearchRoot == null && InIslandsMode())
            {
                // Return error if cDOSearchRoot is not valid in islands/ desktop mode
                throw new InvalidOperationException("Invalid search root");
            }

            XYFocusOptions xyFocusOptions = new XYFocusOptions();

            xyFocusOptions.SearchRoot         = cDOSearchRoot;
            xyFocusOptions.ConsiderEngagement = false;
            xyFocusOptions.IgnoreClipping     = ignoreClipping == true;
            xyFocusOptions.IgnoreCone         = ignoreCone == true;

            candidate = FindNextFocus(focusNavigationDirection, xyFocusOptions);
            return(candidate);
        }
        private static object?FindNextFocus(
            FocusNavigationDirection focusNavigationDirection,
            XYFocusOptions xyFocusOptions)
        {
            if (focusNavigationDirection == FocusNavigationDirection.None)
            {
                throw new ArgumentOutOfRangeException(nameof(focusNavigationDirection));
            }

            var core = DXamlCore.Current;

            if (core == null)
            {
                throw new InvalidOperationException("XamlCore is not set.");
            }

            FocusManager?focusManager = null;

            if (xyFocusOptions.SearchRoot is DependencyObject searchRoot)
            {
                focusManager = VisualTree.GetFocusManagerForElement(searchRoot);
            }
            else if (core.GetHandle().InitializationType == InitializationType.IslandsOnly)
            {
                // Return error if searchRoot is not valid in islands/ desktop mode
                throw new ArgumentException("The search root must not be null.");
            }
            else
            {
                // For compat reasons, these FocusManager static APIs need to always use the CoreWindow as the
                // ContentRoot, so explicitly return the CoreWindow content root.
                var contentRootCoordinator = core.GetHandle().ContentRootCoordinator;
                var contentRoot            = contentRootCoordinator?.CoreWindowContentRoot;

                if (contentRoot == null)
                {
                    return(null);
                }

                focusManager = contentRoot.FocusManager;
            }

            if (focusManager == null)
            {
                return(null);
            }

            var root  = focusManager.ContentRoot;
            var scale = RootScale.GetRasterizationScaleForContentRoot(root);

            ConvertOptionsRectsToPhysical(scale, xyFocusOptions);

            var candidate = focusManager.FindNextFocus(
                new FindFocusOptions(focusNavigationDirection),
                xyFocusOptions);

            return(candidate);
        }
        private static UIElement?FindNextFocusableElementImpl(FocusNavigationDirection focusNavigationDirection)
        {
            if (InIslandsMode())
            {
                // This api is not supported in islands/ desktop mode.
                throw new NotSupportedException("This API is not supported in desktop mode.");
            }

            XYFocusOptions xyFocusOptions = new XYFocusOptions();

            xyFocusOptions.UpdateManifold = false;

            var candidate = FindNextFocus(focusNavigationDirection, xyFocusOptions);

            return(candidate as UIElement);
        }
        private static void ConvertOptionsRectsToPhysical(float scale, XYFocusOptions xyFocusOptions)
        {
            if (xyFocusOptions.ExclusionRect != null)
            {
                Rect exclusionRect = xyFocusOptions.ExclusionRect.Value;
                exclusionRect = DXamlCore.Current.DipsToPhysicalPixels(scale, exclusionRect);
                xyFocusOptions.ExclusionRect = exclusionRect;
            }

            if (xyFocusOptions.FocusHintRectangle != null)
            {
                Rect hintRect = xyFocusOptions.FocusHintRectangle.Value;
                hintRect = DXamlCore.Current.DipsToPhysicalPixels(scale, hintRect);
                xyFocusOptions.FocusHintRectangle = hintRect;
            }
        }
        private static DependencyObject?FindNextElementImpl(FocusNavigationDirection focusNavigationDirection)
        {
            if (InIslandsMode())
            {
                // Return error if FindNextElement is called without focus navigation option in islands/desktop
                if (typeof(FocusManager).Log().IsEnabled(LogLevel.Error))
                {
                    typeof(FocusManager).Log().LogError("FindNextElement override with FindNextElementOptions must be used in WinUI Desktop apps.");
                }
                return(null);
            }

            var xyFocusOptions = new XYFocusOptions
            {
                UpdateManifold = false
            };

            var candidate = FindNextFocus(focusNavigationDirection, xyFocusOptions);

            return(candidate as DependencyObject);
        }
        private object?FindNextFocusWithSearchRootIgnoreEngagementImpl(FocusNavigationDirection focusNavigationDirection, object?pSearchRoot)
        {
            object?          spScope   = pSearchRoot;
            DependencyObject?spScopeDO = spScope as DependencyObject;

            object?candidate;

            var cDOSearchRoot = spScopeDO;

            if (cDOSearchRoot == null && InIslandsMode())
            {
                // Return error if cDOSearchRoot is not valid in islands/ desktop mode
                throw new ArgumentException("Search root must not be null.", nameof(pSearchRoot));
            }

            var xyFocusOptions = new XYFocusOptions();

            xyFocusOptions.SearchRoot         = cDOSearchRoot;
            xyFocusOptions.ConsiderEngagement = false;

            candidate = FindNextFocus(focusNavigationDirection, xyFocusOptions);
            return(candidate);
        }
Example #8
0
 public DependencyObject?FindNextFocus(FindFocusOptions findFocusOptions, XYFocusOptions xyFocusOptions, DependencyObject?component = null, bool updateManifolds = true) =>
 FindNextFocusResult;
        private static DependencyObject?FindNextElementWithOptionsImpl(
            FocusNavigationDirection focusNavigationDirection,
            FindNextElementOptions pFocusNavigationOverride)
        {
            var options = pFocusNavigationOverride;

            var xyFocusOptions = new XYFocusOptions
            {
                UpdateManifold = false
            };

            var searchRoot    = options.SearchRoot;
            var exclusionRect = options.ExclusionRect;
            var hintRect      = options.HintRect;
            var navigationStrategyOverride = options.XYFocusNavigationStrategyOverride;
            var ignoreOcclusivity          = options.IgnoreOcclusivity;

            ContentRoot?contentRoot = null;

            if (searchRoot != null)
            {
                contentRoot = VisualTree.GetContentRootForElement(searchRoot);
            }
            else if (InIslandsMode())
            {
                // Return error if searchRootAsDO is not valid in islands/desktop mode
                throw new InvalidOperationException("Search root is not a dependency object.");
            }
            else
            {
                contentRoot = DXamlCore.Current.GetHandle().ContentRootCoordinator.CoreWindowContentRoot;
            }

            // If we are being passed in the public root visual of the XamlRoot as the SearchRoot, then override the SearchRoot to be the RootVisual.
            // This will enable searching through both the public root visual and the popup root. We will also allow Next/Prev.
            var shouldOverrideSearchRoot =
                contentRoot != null &&
                GetAppVisibleXamlRootContent(contentRoot) == searchRoot;

            if (shouldOverrideSearchRoot)
            {
                searchRoot = contentRoot !.VisualTree.RootElement;
            }
            else
            {
                if (focusNavigationDirection != FocusNavigationDirection.Up &&
                    focusNavigationDirection != FocusNavigationDirection.Down &&
                    focusNavigationDirection != FocusNavigationDirection.Left &&
                    focusNavigationDirection != FocusNavigationDirection.Right)
                {
                    throw new ArgumentOutOfRangeException(
                              "Focus navigation directions Next, Previous, and None " +
                              "are not supported when using FindNextElementOptions");
                }
            }

            if (searchRoot != null)
            {
                xyFocusOptions.SearchRoot = searchRoot;
            }

            if (!exclusionRect.IsUniform)
            {
                xyFocusOptions.ExclusionRect = exclusionRect;
            }

            if (!hintRect.IsUniform)
            {
                xyFocusOptions.FocusHintRectangle = hintRect;
            }

            xyFocusOptions.NavigationStrategyOverride = navigationStrategyOverride;
            xyFocusOptions.IgnoreOcclusivity          = ignoreOcclusivity;

            var candidate = FindNextFocus(focusNavigationDirection, xyFocusOptions);

            return(candidate as DependencyObject);
        }
        private static bool TryMoveFocusStatic(
            FocusNavigationDirection focusNavigationDirection,
            FindNextElementOptions?pFocusNavigationOverride,
            ref IAsyncOperation <FocusMovementResult>?asyncOperation,
            bool useAsync)
        {
            DependencyObject?searchRootAsDO = null;
            Rect             hintRect;
            Rect             exclusionRect;
            XYFocusNavigationStrategyOverride navigationStrategyOverride;
            XYFocusOptions xyFocusOptions = new XYFocusOptions();
            var            pIsFocusMoved  = false;

            FindNextElementOptions?options = pFocusNavigationOverride;

            bool ignoreOcclusivity;
            FocusAsyncOperation?spFocusAsyncOperation = null;

            DXamlCore pCore = DXamlCore.Current;

            if (pCore == null)
            {
                throw new InvalidOperationException("XamlCore is not set.");
            }

            FocusManager?focusManager           = null;
            ContentRoot? contentRoot            = null;
            var          contentRootCoordinator = pCore.GetHandle().ContentRootCoordinator;

            if (options != null)
            {
                var searchRoot = options.SearchRoot;
                exclusionRect = options.ExclusionRect;
                hintRect      = options.HintRect;
                navigationStrategyOverride = options.XYFocusNavigationStrategyOverride;
                ignoreOcclusivity          = options.IgnoreOcclusivity;
                searchRootAsDO             = searchRoot as DependencyObject;

                if (searchRootAsDO != null)
                {
                    contentRoot  = VisualTree.GetContentRootForElement(searchRootAsDO);
                    focusManager = contentRoot?.FocusManager;

                    if (focusManager == null)
                    {
                        throw new InvalidOperationException("Search root is not part of the visual tree.");
                    }
                }
                else if (pCore.GetHandle().InitializationType == InitializationType.IslandsOnly)
                {
                    // SearchRoot must exist for islands/ desktop
                    throw new ArgumentException("The search root must not be null.");
                }
                else
                {
                    contentRoot = contentRootCoordinator?.CoreWindowContentRoot;
                }

                // If we are being passed in the public root visual of a XamlRoot as the SearchRoot, then override the SearchRoot to be the RootVisual.
                // This will enable searching through both the public root visual and the popup root. We will also allow Next/Prev.
                bool shouldOverrideSearchRoot =
                    contentRoot != null &&
                    GetAppVisibleXamlRootContent(contentRoot) == searchRootAsDO;

                if (shouldOverrideSearchRoot)
                {
                    searchRootAsDO = contentRoot !.VisualTree.RootElement;
                }
                else
                {
                    if (focusNavigationDirection != FocusNavigationDirection.Up &&
                        focusNavigationDirection != FocusNavigationDirection.Down &&
                        focusNavigationDirection != FocusNavigationDirection.Left &&
                        focusNavigationDirection != FocusNavigationDirection.Right)
                    {
                        throw new ArgumentOutOfRangeException(
                                  "Focus navigation directions Next, Previous, and None " +
                                  "are not supported when using FindNextElementOptions");
                    }
                }

                xyFocusOptions.NavigationStrategyOverride = navigationStrategyOverride;
                xyFocusOptions.IgnoreOcclusivity          = ignoreOcclusivity;

                Rect exclusionRectNative = exclusionRect;
                Rect hintRectNative      = hintRect;

                if (searchRootAsDO != null)
                {
                    xyFocusOptions.SearchRoot = searchRootAsDO;
                }

                if (!exclusionRectNative.IsUniform)
                {
                    xyFocusOptions.ExclusionRect = exclusionRectNative;
                }

                if (!hintRectNative.IsUniform)
                {
                    xyFocusOptions.FocusHintRectangle = hintRectNative;
                }

                if (contentRoot != null)
                {
                    var scale = RootScale.GetRasterizationScaleForContentRoot(contentRoot);
                    ConvertOptionsRectsToPhysical(scale, xyFocusOptions);
                }
            }

            if (focusManager == null)
            {
                // Return error if call is without focus navigation option in islands/ desktop
                if (pCore.GetHandle().InitializationType == InitializationType.IslandsOnly)
                {
                    throw new InvalidOperationException("Focus navigation options must be set for desktop apps.");
                }

                // For compat reasons, these FocusManager static APIs need to always use the CoreWindow as the
                // ContentRoot, so explicitly return the CoreWindow content root.
                if (contentRoot == null)
                {
                    contentRoot = contentRootCoordinator?.CoreWindowContentRoot;
                }
                if (contentRoot == null)
                {
                    return(pIsFocusMoved);
                }

                focusManager = contentRoot.FocusManager;
            }

            FocusMovement movement = new FocusMovement(xyFocusOptions, focusNavigationDirection, null);

            if (useAsync)
            {
                spFocusAsyncOperation = new FocusAsyncOperation(movement.CorrelationId);
                asyncOperation        = spFocusAsyncOperation.CreateAsyncOperation();

                // Async operation is not guaranteed to be released synchronously.
                // Therefore, we let UpdateFocus to handle the responsibility of releasing it.
                // TODO Uno specific: Do not use async operations, only simulated
                // movement.ShouldCompleteAsyncOperation = focusManager.TrySetAsyncOperation(spFocusAsyncOperation);

                if (movement.ShouldCompleteAsyncOperation)
                {
                    //spFocusAsyncOperation.StartOperation();
                }
            }

            FocusMovementResult result = focusManager.FindAndSetNextFocus(movement);

            // TODO Uno specific: Simulate async completion.
            spFocusAsyncOperation?.CoreSetResults(result);
            spFocusAsyncOperation?.CoreFireCompletion();

            // We ignore result.GetHResult() here because this is a "Try" function
            pIsFocusMoved = result.WasMoved;

            // Async operation is not guaranteed to be released synchronously.
            // Therefore, we let UpdateFocus to handle the responsibility of releasing it.
            //spFocusAsyncOperation.Detach();

            return(pIsFocusMoved);
        }