Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI input refactor #2474

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6f28ba4
Moved picking to separate class, still called from the render method
MechWarrior99 Sep 20, 2024
e110249
Added separate input state for RenderUIElements & changed renderConte…
MechWarrior99 Sep 20, 2024
5c4d628
Removed requirement for RenderDrawContext from UI picking
MechWarrior99 Sep 20, 2024
3c8c2d2
Renamed UIInputPicking to UIInputSystem
MechWarrior99 Sep 20, 2024
4e80cce
Changed UIInputPicking to part of UISystem and got picking working
MechWarrior99 Sep 20, 2024
02dc538
Changed UISystem to use SceneSystem to get cameras
MechWarrior99 Sep 20, 2024
4c1659c
Moved GetWorldViewProjectMatix to standalone method in UISystem
MechWarrior99 Sep 28, 2024
55d0127
Minor refactor of UISystem and renamed RenderUIElement to RenderUIPage
MechWarrior99 Sep 29, 2024
8b5c617
Refactored UISystem to no longer use render objects
MechWarrior99 Sep 29, 2024
04483ef
Small cleanup refactor in UI and moved methods to UIDocumentExtensions
MechWarrior99 Sep 29, 2024
5869d3e
Fixed UI hover state not change when pointer is outside of UI
MechWarrior99 Sep 29, 2024
8707c0b
[Breaking Change] Replaced TouchEventArgs and refactored naming for c…
MechWarrior99 Sep 29, 2024
caabcb9
Fixed UI editor selection and adorners not working
MechWarrior99 Sep 30, 2024
7fabf47
Cleanup and commenting of UI system refactor
MechWarrior99 Oct 3, 2024
955ebee
Removed accidental extra space added in UIRenderFeature
MechWarrior99 Oct 3, 2024
988ef2f
Added missing UI comments and renamed Touch to Pointer where missed
MechWarrior99 Oct 22, 2024
2e45fc9
Added clarifying comments to UIDocument related to its state.
MechWarrior99 Oct 22, 2024
88d2021
Fixed grammar in comment in PointerOverState
MechWarrior99 Oct 22, 2024
29ee52c
Deleted now unused TouchAction enum
MechWarrior99 Oct 22, 2024
b9a74b7
Removed duplicated property IsTouchedDown from Slider
MechWarrior99 Oct 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public SizingAdorner(UIEditorGameAdornerService service, UIElement gameSideEleme
ResizingDirection = resizingDirection;

// support for mouse over cursor
Visual.MouseOverStateChanged += MouseOverStateChanged;
Visual.MouseOverStateChanged += PointerOverStateChanged;
}

public ResizingDirection ResizingDirection
Expand Down Expand Up @@ -147,12 +147,12 @@ void IResizingAdorner.OnResizingCompleted()
isDragging = false;
}

private void MouseOverStateChanged(object sender, PropertyChangedArgs<MouseOverState> e)
private void PointerOverStateChanged(object sender, PropertyChangedArgs<PointerOverState> e)
{
if (isDragging)
return;

Service.Controller.ChangeCursor(e.NewValue != MouseOverState.MouseOverNone ? GetCursor() : null);
Service.Controller.ChangeCursor(e.NewValue != PointerOverState.None ? GetCursor() : null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ internal void ApplyChanges(Guid elementId, IReadOnlyDictionary<string, object> c
}

#region Event Handlers
private void PreviewTouchDown(object sender, TouchEventArgs e)
private void PreviewPointerPressed(object sender, PointerEventArgs e)
{
if (!Game.Input.IsMouseButtonDown(MouseButton.Left))
return;

// Save the current pointer position
originWorldPosition = currentPosition = e.WorldPosition;
originScreenPosition = e.ScreenPosition;
originScreenPosition = e.Position;

// No prior selection (selection is done on TouchUp)
if (selectedAdorners.Count == 0)
Expand Down Expand Up @@ -115,13 +115,13 @@ orderby hit.IntersectionPoint.Z
isInProgress = true;
}

private void PreviewTouchMove(object sender, TouchEventArgs e)
private void PreviewPointerMove(object sender, PointerEventArgs e)
{
var worldPosition = e.WorldPosition;
DoHighlightingAtPosition(ref worldPosition);
}

private void TouchMove(object sender, TouchEventArgs e)
private void PointerMove(object sender, PointerEventArgs e)
{
// dragging state
if (isInProgress)
Expand All @@ -134,7 +134,7 @@ private void TouchMove(object sender, TouchEventArgs e)
if (!isDragging)
{
// Start dragging only if a minimum distance is reached (on the real screen, not the virtual screen).
var delta = (e.ScreenPosition - originScreenPosition)*new Vector2(Game.GraphicsDevice.Presenter.BackBuffer.Width, Game.GraphicsDevice.Presenter.BackBuffer.Height);
var delta = (e.Position - originScreenPosition)*new Vector2(Game.GraphicsDevice.Presenter.BackBuffer.Width, Game.GraphicsDevice.Presenter.BackBuffer.Height);
if (Math.Abs(delta.X) > System.Windows.SystemParameters.MinimumHorizontalDragDistance || Math.Abs(delta.Y) > System.Windows.SystemParameters.MinimumVerticalDragDistance)
{
isDragging = true;
Expand Down Expand Up @@ -183,7 +183,7 @@ private void TouchMove(object sender, TouchEventArgs e)
// TODO: special case when trying to move when there is nothing selected: should select and start moving at the same time
}

private void TouchUp(object sender, TouchEventArgs e)
private void PointerReleased(object sender, PointerEventArgs e)
{
if (!Game.Input.IsMouseButtonReleased(MouseButton.Left))
return;
Expand Down Expand Up @@ -231,7 +231,7 @@ private void TouchUp(object sender, TouchEventArgs e)
}

// Select the corresponding asset-side UIElement, if pointer did not move between down and up events
var delta = (e.ScreenPosition - originScreenPosition)*new Vector2(Game.GraphicsDevice.Presenter.BackBuffer.Width, Game.GraphicsDevice.Presenter.BackBuffer.Height);
var delta = (e.Position - originScreenPosition)*new Vector2(Game.GraphicsDevice.Presenter.BackBuffer.Width, Game.GraphicsDevice.Presenter.BackBuffer.Height);
if (Math.Abs(delta.X) < System.Windows.SystemParameters.MinimumHorizontalDragDistance && Math.Abs(delta.Y) < System.Windows.SystemParameters.MinimumVerticalDragDistance)
{
var additiveSelection = Game.Input.IsKeyDown(Keys.LeftCtrl) || Game.Input.IsKeyDown(Keys.RightCtrl);
Expand Down Expand Up @@ -273,7 +273,7 @@ private void DoHighlightingAtPosition(ref Vector3 worldPosition)
DoHighlightAdorner(elementId);
}

private ICollection<UIRenderFeature.HitTestResult> GetAdornerVisualsAtPosition(ref Vector3 worldPosition)
private ICollection<UISystem.HitTestResult> GetAdornerVisualsAtPosition(ref Vector3 worldPosition)
{
var uiComponent = Controller.GetEntityByName(UIEditorController.AdornerEntityName).Get<UIComponent>();
if (Math.Abs(worldPosition.X) > uiComponent.Resolution.X * 0.5f ||
Expand All @@ -286,7 +286,7 @@ private void DoHighlightingAtPosition(ref Vector3 worldPosition)

var ray = new Ray(new Vector3(worldPosition.X, worldPosition.Y, uiComponent.Resolution.Z + 1), -Vector3.UnitZ);
var worldViewProj = Matrix.Identity; // All the calculation is done in UI space
return UIRenderFeature.GetElementsAtPosition(rootElement, ref ray, ref worldViewProj);
return UISystem.GetElementsAtPosition(rootElement, ref ray, ref worldViewProj);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -524,10 +524,10 @@ private async Task Update()
if (adornerCanvas == null)
continue;

adornerCanvas.PreviewTouchDown += PreviewTouchDown;
adornerCanvas.PreviewTouchMove += PreviewTouchMove;
adornerCanvas.TouchMove += TouchMove;
adornerCanvas.TouchUp += TouchUp;
adornerCanvas.PreviewPointerPressed += PreviewPointerPressed;
adornerCanvas.PreviewPointerMove += PreviewPointerMove;
adornerCanvas.PointerMove += PointerMove;
adornerCanvas.PointerReleased += PointerReleased;
break;
}

Expand Down
6 changes: 5 additions & 1 deletion sources/engine/Stride.Input/PointerEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace Stride.Input
{
/// <summary>
/// A pointer event.
/// A pointer event. A pointer is a mouse, pen, finger, or other touch.
/// </summary>
public class PointerEvent : InputEvent
{
Expand All @@ -23,24 +23,28 @@ public class PointerEvent : InputEvent
/// Gets the absolute screen position of the pointer.
/// </summary>
/// <value>The absolute delta position.</value>
/// <remarks>AbsolutePosition is between [0, SurfaceSize]. (0, 0) is the left top corner, (SurfaceSize.X, SurfaceSize.Y) is the right bottom corner.</remarks>
public Vector2 AbsolutePosition => Position * Pointer.SurfaceSize;

/// <summary>
/// Gets the normalized screen position of the pointer.
/// </summary>
/// <value>The position.</value>
/// <remarks>Position is normalized between [0,1]. (0,0) is the left top corner, (1,1) is the right bottom corner.</remarks>
public Vector2 Position { get; internal set; }

/// <summary>
/// Gets the absolute delta position of the pointer since the previous frame.
/// </summary>
/// <value>The absolute delta position.</value>
/// <remarks>AbsoluteDeltaPosition position space is between [0, SurfaceSize]. (0, 0) is the left top corner, (SurfaceSize.X, SurfaceSize.Y) is the right bottom corner.</remarks>
public Vector2 AbsoluteDeltaPosition => DeltaPosition * Pointer.SurfaceSize;

/// <summary>
/// Gets the delta position of the pointer since the previous frame.
/// </summary>
/// <value>The delta position.</value>
/// <remarks>DeltaPosition position space is normalized between [0,1]. (0,0) is the left top corner, (1,1) is the right bottom corner.</remarks>
public Vector2 DeltaPosition { get; internal set; }

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion sources/engine/Stride.UI.Tests/Regression/ButtonTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected override void RegisterTests()

private void DrawTest1()
{
button.RaiseTouchDownEvent(new TouchEventArgs());
button.RaisePointerPressedEvent(new TouchEventArgs());
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected override void RegisterTests()

private void DrawTest1()
{
button.RaiseTouchDownEvent(new TouchEventArgs());
button.RaisePointerPressedEvent(new TouchEventArgs());
}

[Fact]
Expand Down
80 changes: 40 additions & 40 deletions sources/engine/Stride.UI.Tests/Regression/MouseOverTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ public class MouseOverTest : UITestGameBase
private bool triggeredCanvas;
private bool triggeredStackPanel;

private MouseOverState oldValueButton1;
private MouseOverState newValueButton1;
private PointerOverState oldValueButton1;
private PointerOverState newValueButton1;

public MouseOverTest()
{
Expand Down Expand Up @@ -119,12 +119,12 @@ private void Test1()
{
ResetStates();

Assert.Equal(MouseOverState.MouseOverNone, canvas.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, stackPanel.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, button1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, button2.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, edit1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, edit2.MouseOverState);
Assert.Equal(PointerOverState.None, canvas.PointerOverState);
Assert.Equal(PointerOverState.None, stackPanel.PointerOverState);
Assert.Equal(PointerOverState.None, button1.PointerOverState);
Assert.Equal(PointerOverState.None, button2.PointerOverState);
Assert.Equal(PointerOverState.None, edit1.PointerOverState);
Assert.Equal(PointerOverState.None, edit2.PointerOverState);

Assert.False(triggeredButton1);
Assert.False(triggeredButton2);
Expand All @@ -143,12 +143,12 @@ private void PrepareTest2()

private void Test2()
{
Assert.Equal(MouseOverState.MouseOverChild, canvas.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, stackPanel.MouseOverState);
Assert.Equal(MouseOverState.MouseOverElement, button1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, button2.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, edit1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, edit2.MouseOverState);
Assert.Equal(PointerOverState.Child, canvas.PointerOverState);
Assert.Equal(PointerOverState.None, stackPanel.PointerOverState);
Assert.Equal(PointerOverState.Self, button1.PointerOverState);
Assert.Equal(PointerOverState.None, button2.PointerOverState);
Assert.Equal(PointerOverState.None, edit1.PointerOverState);
Assert.Equal(PointerOverState.None, edit2.PointerOverState);

Assert.True(triggeredButton1);
Assert.True(triggeredCanvas);
Expand All @@ -157,8 +157,8 @@ private void Test2()
Assert.False(triggeredEdit2);
Assert.False(triggeredStackPanel);

Assert.Equal(MouseOverState.MouseOverNone, oldValueButton1);
Assert.Equal(MouseOverState.MouseOverElement, newValueButton1);
Assert.Equal(PointerOverState.None, oldValueButton1);
Assert.Equal(PointerOverState.Self, newValueButton1);
}

private void PrepareTest3()
Expand All @@ -170,12 +170,12 @@ private void PrepareTest3()

private void Test3()
{
Assert.Equal(MouseOverState.MouseOverChild, canvas.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, stackPanel.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, button1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, button2.MouseOverState);
Assert.Equal(MouseOverState.MouseOverElement, edit1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, edit2.MouseOverState);
Assert.Equal(PointerOverState.Child, canvas.PointerOverState);
Assert.Equal(PointerOverState.None, stackPanel.PointerOverState);
Assert.Equal(PointerOverState.None, button1.PointerOverState);
Assert.Equal(PointerOverState.None, button2.PointerOverState);
Assert.Equal(PointerOverState.Self, edit1.PointerOverState);
Assert.Equal(PointerOverState.None, edit2.PointerOverState);

Assert.True(triggeredButton1);
Assert.True(triggeredEdit1);
Expand All @@ -194,12 +194,12 @@ private void PrepareTest4()

private void Test4()
{
Assert.Equal(MouseOverState.MouseOverElement, canvas.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, stackPanel.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, button1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, button2.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, edit1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, edit2.MouseOverState);
Assert.Equal(PointerOverState.Self, canvas.PointerOverState);
Assert.Equal(PointerOverState.None, stackPanel.PointerOverState);
Assert.Equal(PointerOverState.None, button1.PointerOverState);
Assert.Equal(PointerOverState.None, button2.PointerOverState);
Assert.Equal(PointerOverState.None, edit1.PointerOverState);
Assert.Equal(PointerOverState.None, edit2.PointerOverState);

Assert.True(triggeredEdit1);
Assert.True(triggeredCanvas);
Expand All @@ -218,12 +218,12 @@ private void PrepareTest5()

private void Test5()
{
Assert.Equal(MouseOverState.MouseOverChild, canvas.MouseOverState);
Assert.Equal(MouseOverState.MouseOverChild, stackPanel.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, button1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverElement, button2.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, edit1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, edit2.MouseOverState);
Assert.Equal(PointerOverState.Child, canvas.PointerOverState);
Assert.Equal(PointerOverState.Child, stackPanel.PointerOverState);
Assert.Equal(PointerOverState.None, button1.PointerOverState);
Assert.Equal(PointerOverState.Self, button2.PointerOverState);
Assert.Equal(PointerOverState.None, edit1.PointerOverState);
Assert.Equal(PointerOverState.None, edit2.PointerOverState);

Assert.True(triggeredCanvas);
Assert.True(triggeredButton2);
Expand All @@ -242,12 +242,12 @@ private void PrepareTest6()

private void Test6()
{
Assert.Equal(MouseOverState.MouseOverChild, canvas.MouseOverState);
Assert.Equal(MouseOverState.MouseOverChild, stackPanel.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, button1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, button2.MouseOverState);
Assert.Equal(MouseOverState.MouseOverNone, edit1.MouseOverState);
Assert.Equal(MouseOverState.MouseOverElement, edit2.MouseOverState);
Assert.Equal(PointerOverState.Child, canvas.PointerOverState);
Assert.Equal(PointerOverState.Child, stackPanel.PointerOverState);
Assert.Equal(PointerOverState.None, button1.PointerOverState);
Assert.Equal(PointerOverState.None, button2.PointerOverState);
Assert.Equal(PointerOverState.None, edit1.PointerOverState);
Assert.Equal(PointerOverState.Self, edit2.PointerOverState);

Assert.True(triggeredEdit2);
Assert.True(triggeredButton2);
Expand Down
2 changes: 1 addition & 1 deletion sources/engine/Stride.UI/Controls/Button.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public bool SizeToContent
}
}

internal ISpriteProvider ButtonImageProvider => IsPressed ? PressedImage : (MouseOverState == MouseOverState.MouseOverElement && MouseOverImage != null ? MouseOverImage : NotPressedImage);
internal ISpriteProvider ButtonImageProvider => IsPressed ? PressedImage : (PointerOverState == PointerOverState.Self && MouseOverImage != null ? MouseOverImage : NotPressedImage);

internal Sprite ButtonImage => ButtonImageProvider?.GetSprite();

Expand Down
12 changes: 6 additions & 6 deletions sources/engine/Stride.UI/Controls/ButtonBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,29 @@ public event EventHandler<RoutedEventArgs> Click
typeof(Button));


protected override void OnTouchDown(TouchEventArgs args)
protected override void OnPointerPressed(PointerEventArgs args)
{
base.OnTouchDown(args);
base.OnPointerPressed(args);

IsPressed = true;

if (ClickMode == ClickMode.Press)
RaiseEvent(new RoutedEventArgs(ClickEvent));
}

protected override void OnTouchUp(TouchEventArgs args)
protected override void OnPointerReleased(PointerEventArgs args)
{
base.OnTouchUp(args);
base.OnPointerReleased(args);

if (IsPressed && ClickMode == ClickMode.Release)
RaiseEvent(new RoutedEventArgs(ClickEvent));

IsPressed = false;
}

protected override void OnTouchLeave(TouchEventArgs args)
protected override void OnPointerLeave(PointerEventArgs args)
{
base.OnTouchLeave(args);
base.OnPointerLeave(args);

IsPressed = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private void UpdateSelectionToEditImpl()
{
}

private void OnTouchUpImpl(TouchEventArgs args)
private void OnPointerReleasedImpl(PointerEventArgs args)
{
}
}
Expand Down
4 changes: 2 additions & 2 deletions sources/engine/Stride.UI/Controls/EditText.Direct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Stride.UI.Controls
{
public partial class EditText
{
private void OnTouchMoveImpl(TouchEventArgs args)
private void OnPointerMoveImpl(PointerEventArgs args)
{
var currentPosition = FindNearestCharacterIndex(new Vector2(args.WorldPosition.X - WorldMatrix.M41, args.WorldPosition.Y - WorldMatrix.M42));

Expand All @@ -33,7 +33,7 @@ private void OnTouchMoveImpl(TouchEventArgs args)
}
}

private void OnTouchDownImpl(TouchEventArgs args)
private void OnPointerPressedImpl(PointerEventArgs args)
{
// Find the appropriate position for the caret.
CaretPosition = FindNearestCharacterIndex(new Vector2(args.WorldPosition.X - WorldMatrix.M41, args.WorldPosition.Y - WorldMatrix.M42));
Expand Down
Loading