From 0293ea435ee93a1cd85290f0e7dda2cb1d988ff5 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Wed, 8 Nov 2023 10:31:36 +0100 Subject: [PATCH] Added UiControls.NavType, which stores the most recently used type of ui navigation --- CHANGELOG.md | 3 ++ MLEM.Ui/UiControls.cs | 66 +++++++++++++++++++++++++++++++++++++++++-- MLEM.Ui/UiSystem.cs | 7 +++-- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cd7aae..4c025d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,9 @@ Fixes - Fixed TextInput not working correctly when using surrogate pairs ### MLEM.Ui +Additions +- Added UiControls.NavType, which stores the most recently used type of ui navigation + Improvements - Allow scrolling panels to contain other scrolling panels - Allow dropdowns to have scrolling panels diff --git a/MLEM.Ui/UiControls.cs b/MLEM.Ui/UiControls.cs index ec69172..a8d35ad 100644 --- a/MLEM.Ui/UiControls.cs +++ b/MLEM.Ui/UiControls.cs @@ -103,7 +103,7 @@ namespace MLEM.Ui { /// public bool HandleGamepad = true; /// - /// If this value is true, the ui controls are in automatic navigation mode. + /// If this value is true, the ui controls are in automatic navigation mode. The state of automatic navigation is usually based on the current . /// This means that the will be drawn around the . /// public bool IsAutoNavMode { @@ -115,12 +115,29 @@ namespace MLEM.Ui { } } } + /// + /// The current of these ui controls, which represents the last type of interaction that was used to interact with the underlying . + /// + public NavigationType NavType { + get => this.navType; + set { + if (this.navType != value) { + var last = this.navType; + this.navType = value; + this.NavTypeChanged?.Invoke(last, value); + } + } + } /// /// An event that is raised when is changed. /// This can be used for custom actions like hiding the mouse cursor when automatic navigation is enabled. /// public event Action AutoNavModeChanged; + /// + /// An event that is raised when is changed. It receives the previous navigation type, as well as the newly set navigation type. + /// + public event Action NavTypeChanged; /// /// This value ist true if the was created by this ui controls instance, or if it was passed in. @@ -134,6 +151,7 @@ namespace MLEM.Ui { private readonly Dictionary selectedElements = new Dictionary(); private bool isAutoNavMode; + private NavigationType navType; /// /// Creates a new instance of the ui controls. @@ -167,6 +185,7 @@ namespace MLEM.Ui { if (this.Input.IsPressedAvailable(MouseButton.Left)) { this.IsAutoNavMode = false; + this.NavType = NavigationType.Mouse; var selectedNow = mousedNow != null && mousedNow.CanBeSelected ? mousedNow : null; this.SelectElement(this.ActiveRoot, selectedNow); if (mousedNow != null && mousedNow.CanBePressed) { @@ -175,6 +194,7 @@ namespace MLEM.Ui { } } else if (this.Input.IsPressedAvailable(MouseButton.Right)) { this.IsAutoNavMode = false; + this.NavType = NavigationType.Mouse; if (mousedNow != null && mousedNow.CanBePressed) { this.PressElement(mousedNow, true); this.Input.TryConsumePressed(MouseButton.Right); @@ -187,12 +207,14 @@ namespace MLEM.Ui { if (this.HandleKeyboard) { if (this.KeyboardButtons.IsPressedAvailable(this.Input, this.GamepadIndex)) { if (this.SelectedElement?.Root != null && this.SelectedElement.CanBePressed) { + this.NavType = NavigationType.Keyboard; // primary or secondary action on element using space or enter this.PressElement(this.SelectedElement, this.Input.IsModifierKeyDown(ModifierKey.Shift)); this.KeyboardButtons.TryConsumePressed(this.Input, this.GamepadIndex); } } else if (this.Input.IsPressedAvailable(Keys.Tab)) { this.IsAutoNavMode = true; + this.NavType = NavigationType.Keyboard; // tab or shift-tab to next or previous element var backward = this.Input.IsModifierKeyDown(ModifierKey.Shift); var next = this.GetTabNextElement(backward); @@ -208,12 +230,14 @@ namespace MLEM.Ui { if (this.HandleTouch) { if (this.Input.GetViewportGesture(GestureType.Tap, out var tap)) { this.IsAutoNavMode = false; + this.NavType = NavigationType.Touch; var tapped = this.GetElementUnderPos(tap.Position); this.SelectElement(this.ActiveRoot, tapped); if (tapped != null && tapped.CanBePressed) this.PressElement(tapped); } else if (this.Input.GetViewportGesture(GestureType.Hold, out var hold)) { this.IsAutoNavMode = false; + this.NavType = NavigationType.Touch; var held = this.GetElementUnderPos(hold.Position); this.SelectElement(this.ActiveRoot, held); if (held != null && held.CanBePressed) @@ -224,6 +248,7 @@ namespace MLEM.Ui { foreach (var location in this.Input.ViewportTouchState) { var element = this.GetElementUnderPos(location.Position); if (location.State == TouchLocationState.Pressed) { + this.NavType = NavigationType.Touch; // start touching an element if we just touched down on it this.SetTouchedElement(element); } else if (element != this.TouchedElement) { @@ -239,11 +264,13 @@ namespace MLEM.Ui { if (this.HandleGamepad) { if (this.GamepadButtons.IsPressedAvailable(this.Input, this.GamepadIndex)) { if (this.SelectedElement?.Root != null && this.SelectedElement.CanBePressed) { + this.NavType = NavigationType.Gamepad; this.PressElement(this.SelectedElement); this.GamepadButtons.TryConsumePressed(this.Input, this.GamepadIndex); } } else if (this.SecondaryGamepadButtons.IsPressedAvailable(this.Input, this.GamepadIndex)) { if (this.SelectedElement?.Root != null && this.SelectedElement.CanBePressed) { + this.NavType = NavigationType.Gamepad; this.PressElement(this.SelectedElement, true); this.SecondaryGamepadButtons.TryConsumePressed(this.Input, this.GamepadIndex); } @@ -286,8 +313,9 @@ namespace MLEM.Ui { /// /// The root element of the /// The element to select, or null to deselect the selected element. - /// Whether automatic navigation should be forced on - public void SelectElement(RootElement root, Element element, bool? autoNav = null) { + /// Whether automatic navigation should be forced on. If this is , the automatic navigation state will stay the same. + /// An optional to set. If this is , the navigation type will stay the same. + public void SelectElement(RootElement root, Element element, bool? autoNav = null, NavigationType? navType = null) { if (root == null) return; if (element != null && !element.CanBeSelected) @@ -308,6 +336,8 @@ namespace MLEM.Ui { if (autoNav != null) this.IsAutoNavMode = autoNav.Value; + if (navType != null) + this.NavType = navType.Value; } /// @@ -444,6 +474,7 @@ namespace MLEM.Ui { private bool HandleGamepadNextElement(Direction2 dir) { this.IsAutoNavMode = true; + this.NavType = NavigationType.Gamepad; var next = this.GetGamepadNextElement(dir); if (this.SelectedElement != null) next = this.SelectedElement.GetGamepadNextElement(dir, next); @@ -454,5 +485,34 @@ namespace MLEM.Ui { return false; } + /// + /// An enumeration type that represents the possible types of navigation that a instance supports. + /// This is used by , which stores the most recently used navigation type for a . + /// + public enum NavigationType { + + /// + /// An unknown navigation type, which usually means there has not been any ui navigation of any type yet. + /// + Unknown = 0, + /// + /// Mouse cursor and mouse button navigation. + /// + Mouse, + /// + /// Keyboard navigation. + /// + Keyboard, + /// + /// Touch and gesture navigation. + /// + Touch, + /// + /// Gamepad-style navigation, which may also include arrow key-based navigation based on current settings. + /// + Gamepad + + } + } } diff --git a/MLEM.Ui/UiSystem.cs b/MLEM.Ui/UiSystem.cs index a96c4f2..2e80d72 100644 --- a/MLEM.Ui/UiSystem.cs +++ b/MLEM.Ui/UiSystem.cs @@ -608,9 +608,10 @@ namespace MLEM.Ui { /// Optionally, automatic navigation can be forced on, causing the to be drawn around the element. /// /// The element to select, or null to deselect the selected element. - /// Whether automatic navigation should be forced on - public void SelectElement(Element element, bool? autoNav = null) { - this.System.Controls.SelectElement(this, element, autoNav); + /// Whether automatic navigation should be forced on. If this is , the automatic navigation state will stay the same. + /// An optional to set. If this is , the navigation type will stay the same. + public void SelectElement(Element element, bool? autoNav = null, UiControls.NavigationType? navType = null) { + this.System.Controls.SelectElement(this, element, autoNav, navType); } ///