From 963300c2cbe2f4906e4ea5f1c37ed1a30c74e23b Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sat, 23 Sep 2023 11:56:45 +0200 Subject: [PATCH] - Implemented shift tab support for Container Controls --- Source/Editor/GUI/Dialogs/Dialog.cs | 6 ++++- Source/Editor/Windows/EditorWindow.cs | 3 ++- Source/Engine/UI/GUI/ContainerControl.cs | 28 +++++++++++++++++++----- Source/Engine/UI/GUI/Control.cs | 1 + Source/Engine/UI/GUI/Enums.cs | 5 +++++ 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/Source/Editor/GUI/Dialogs/Dialog.cs b/Source/Editor/GUI/Dialogs/Dialog.cs index 8910cfe49..c7d565f9c 100644 --- a/Source/Editor/GUI/Dialogs/Dialog.cs +++ b/Source/Editor/GUI/Dialogs/Dialog.cs @@ -290,7 +290,11 @@ namespace FlaxEditor.GUI.Dialogs OnCancel(); return true; case KeyboardKeys.Tab: - Root?.Navigate(NavDirection.Next); + if (Root != null) + { + bool shiftDown = Root.GetKey(KeyboardKeys.Shift); + Root?.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next); + } return true; } return false; diff --git a/Source/Editor/Windows/EditorWindow.cs b/Source/Editor/Windows/EditorWindow.cs index 1ff0363f1..60817a51b 100644 --- a/Source/Editor/Windows/EditorWindow.cs +++ b/Source/Editor/Windows/EditorWindow.cs @@ -207,7 +207,8 @@ namespace FlaxEditor.Windows case KeyboardKeys.Tab: if (CanUseNavigation && Root != null) { - Root.Navigate(NavDirection.Next); + bool shiftDown = Root.GetKey(KeyboardKeys.Shift); + Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next); return true; } break; diff --git a/Source/Engine/UI/GUI/ContainerControl.cs b/Source/Engine/UI/GUI/ContainerControl.cs index 2de96d0b3..d8d5c6e5f 100644 --- a/Source/Engine/UI/GUI/ContainerControl.cs +++ b/Source/Engine/UI/GUI/ContainerControl.cs @@ -507,15 +507,19 @@ namespace FlaxEngine.GUI // Perform automatic navigation based on the layout var result = NavigationRaycast(direction, location, visited); - if (result == null && direction == NavDirection.Next) + var rightMostLocation = location; + if (result == null && (direction == NavDirection.Next || direction == NavDirection.Previous)) { // Try wrap the navigation over the layout based on the direction var visitedWrap = new List(visited); - result = NavigationWrap(direction, location, visitedWrap); + result = NavigationWrap(direction, location, visitedWrap, out rightMostLocation); } if (result != null) { - result = result.OnNavigate(direction, result.PointFromParent(location), this, visited); + // HACK: only the 'previous' direction needs the rightMostLocation so i used a ternary conditional operator. + // The rightMostLocation can probably become a 'desired raycast origin' that gets calculated correctly in the NavigationWrap method. + var useLocation = direction == NavDirection.Previous ? rightMostLocation : location; + result = result.OnNavigate(direction, result.PointFromParent(useLocation), this, visited); if (result != null) return result; } @@ -551,8 +555,9 @@ namespace FlaxEngine.GUI /// The navigation direction. /// The navigation start location (in the control-space). /// The list with visited controls. Used to skip recursive navigation calls when doing traversal across the UI hierarchy. + /// Returns the rightmost location of the parent container for the raycast used by the child container /// The target navigation control or null if didn't performed any navigation. - protected virtual Control NavigationWrap(NavDirection direction, Float2 location, List visited) + protected virtual Control NavigationWrap(NavDirection direction, Float2 location, List visited, out Float2 rightMostLocation) { // This searches form a child that calls this navigation event (see Control.OnNavigate) to determinate the layout wrapping size based on that child size var currentChild = RootWindow?.FocusedControl; @@ -566,15 +571,22 @@ namespace FlaxEngine.GUI case NavDirection.Next: predictedLocation = new Float2(0, location.Y + layoutSize.Y); break; + case NavDirection.Previous: + predictedLocation = new Float2(Size.X, location.Y - layoutSize.Y); + break; } if (new Rectangle(Float2.Zero, Size).Contains(ref predictedLocation)) { var result = NavigationRaycast(direction, predictedLocation, visited); if (result != null) - return result; + { + rightMostLocation = predictedLocation; + return result; + } } } - return Parent?.NavigationWrap(direction, PointToParent(ref location), visited); + rightMostLocation = location; + return Parent?.NavigationWrap(direction, PointToParent(ref location), visited, out rightMostLocation); } private static bool CanGetAutoFocus(Control c) @@ -613,6 +625,10 @@ namespace FlaxEngine.GUI uiDir1 = new Float2(1, 0); uiDir2 = new Float2(0, 1); break; + case NavDirection.Previous: + uiDir1 = new Float2(-1, 0); + uiDir2 = new Float2(0, -1); + break; } Control result = null; var minDistance = float.MaxValue; diff --git a/Source/Engine/UI/GUI/Control.cs b/Source/Engine/UI/GUI/Control.cs index 3bc2610a4..747d407e9 100644 --- a/Source/Engine/UI/GUI/Control.cs +++ b/Source/Engine/UI/GUI/Control.cs @@ -634,6 +634,7 @@ namespace FlaxEngine.GUI case NavDirection.Left: return new Float2(0, size.Y * 0.5f); case NavDirection.Right: return new Float2(size.X, size.Y * 0.5f); case NavDirection.Next: return Float2.Zero; + case NavDirection.Previous: return new Float2(Size.X, Size.Y); default: return size * 0.5f; } } diff --git a/Source/Engine/UI/GUI/Enums.cs b/Source/Engine/UI/GUI/Enums.cs index d0b4fb61c..9672dcb9b 100644 --- a/Source/Engine/UI/GUI/Enums.cs +++ b/Source/Engine/UI/GUI/Enums.cs @@ -202,5 +202,10 @@ namespace FlaxEngine.GUI /// The next item (right with layout wrapping). /// Next, + + /// + /// The previous item (left with layout wrapping). + /// + Previous, } }