Browse Source

Merge pull request #12666 from AvaloniaUI/gesture_cancel

Call CaptureLost on gestures when pointer loses capture
release/11.0.5-rc1
Max Katz 2 years ago
committed by Steven Kirk
parent
commit
6fd494ab16
  1. 15
      src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs
  2. 4
      src/Avalonia.Base/Input/GestureRecognizers/PinchGestureRecognizer.cs
  3. 6
      src/Avalonia.Base/Input/InputElement.cs
  4. 8
      src/Avalonia.Base/Input/Pointer.cs
  5. 34
      tests/Avalonia.Base.UnitTests/Input/GesturesTests.cs
  6. 6
      tests/Avalonia.UnitTests/TouchTestHelper.cs

15
src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs

@ -1,3 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Avalonia.Controls;
@ -59,6 +60,20 @@ namespace Avalonia.Input.GestureRecognizers
return e.Handled;
}
internal void HandleCaptureLost(IPointer pointer)
{
if (_recognizers == null || pointer is not Pointer p)
return;
foreach (var r in _recognizers)
{
if (p.CapturedGestureRecognizer == r)
continue;
r.PointerCaptureLostInternal(pointer);
}
}
internal bool HandlePointerReleased(PointerReleasedEventArgs e)
{
if (_recognizers == null)

4
src/Avalonia.Base/Input/GestureRecognizers/PinchGestureRecognizer.cs

@ -1,4 +1,5 @@
using Avalonia.Input.GestureRecognizers;
using System.Diagnostics;
using Avalonia.Input.GestureRecognizers;
namespace Avalonia.Input
{
@ -110,6 +111,7 @@ namespace Avalonia.Input
_secondContact = null;
}
Target?.RaiseEvent(new PinchEndedEventArgs());
}
}

6
src/Avalonia.Base/Input/InputElement.cs

@ -230,6 +230,7 @@ namespace Avalonia.Input
PointerMovedEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerMoved(e), handledEventsToo: true);
PointerPressedEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerPressed(e), handledEventsToo: true);
PointerReleasedEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerReleased(e), handledEventsToo: true);
PointerCaptureLostEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerCaptureLost(e), handledEventsToo: true);
}
public InputElement()
@ -615,6 +616,11 @@ namespace Avalonia.Input
}
}
private void OnGesturePointerCaptureLost(PointerCaptureLostEventArgs e)
{
_gestureRecognizers?.HandleCaptureLost(e.Pointer);
}
private void OnGesturePointerPressed(PointerPressedEventArgs e)
{
if (!e.IsGestureRecognitionSkipped)

8
src/Avalonia.Base/Input/Pointer.cs

@ -91,12 +91,16 @@ namespace Avalonia.Input
internal void CaptureGestureRecognizer(GestureRecognizer? gestureRecognizer)
{
if (CapturedGestureRecognizer != gestureRecognizer)
{
CapturedGestureRecognizer?.PointerCaptureLostInternal(this);
}
CapturedGestureRecognizer = gestureRecognizer;
if (gestureRecognizer != null)
{
Capture(null);
CapturedGestureRecognizer = gestureRecognizer;
}
}
}
}

34
tests/Avalonia.Base.UnitTests/Input/GesturesTests.cs

@ -487,6 +487,40 @@ namespace Avalonia.Base.UnitTests.Input
Assert.True(raised);
}
[Fact]
public void Gestures_Should_Be_Cancelled_When_Pointer_Capture_Is_Lost()
{
Border border = new Border()
{
Width = 100,
Height = 100,
Background = new SolidColorBrush(Colors.Red)
};
border.GestureRecognizers.Add(new PinchGestureRecognizer());
var root = new TestRoot
{
Child = border
};
var raised = false;
root.AddHandler(Gestures.PinchEvent, (_, _) => raised = true);
var firstPoint = new Point(5, 5);
var secondPoint = new Point(10, 10);
var firstTouch = new TouchTestHelper();
var secondTouch = new TouchTestHelper();
firstTouch.Down(border, position: firstPoint);
firstTouch.Cancel();
secondTouch.Down(border, position: secondPoint);
secondTouch.Move(border, position: new Point(20, 20));
Assert.False(raised);
}
[Fact]
public void Scrolling_Should_Start_After_Start_Distance_Is_Exceeded()
{

6
tests/Avalonia.UnitTests/TouchTestHelper.cs

@ -61,5 +61,11 @@ namespace Avalonia.UnitTests
Down(target, source, position, modifiers);
Up(target, source, position, modifiers);
}
public void Cancel()
{
_pointer.Capture(null);
_pointer.CaptureGestureRecognizer(null);
}
}
}

Loading…
Cancel
Save