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 3 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;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Controls; using Avalonia.Controls;
@ -59,6 +60,20 @@ namespace Avalonia.Input.GestureRecognizers
return e.Handled; 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) internal bool HandlePointerReleased(PointerReleasedEventArgs e)
{ {
if (_recognizers == null) 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 namespace Avalonia.Input
{ {
@ -110,6 +111,7 @@ namespace Avalonia.Input
_secondContact = null; _secondContact = null;
} }
Target?.RaiseEvent(new PinchEndedEventArgs()); 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); PointerMovedEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerMoved(e), handledEventsToo: true);
PointerPressedEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerPressed(e), handledEventsToo: true); PointerPressedEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerPressed(e), handledEventsToo: true);
PointerReleasedEvent.AddClassHandler<InputElement>((x, e) => x.OnGesturePointerReleased(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() public InputElement()
@ -615,6 +616,11 @@ namespace Avalonia.Input
} }
} }
private void OnGesturePointerCaptureLost(PointerCaptureLostEventArgs e)
{
_gestureRecognizers?.HandleCaptureLost(e.Pointer);
}
private void OnGesturePointerPressed(PointerPressedEventArgs e) private void OnGesturePointerPressed(PointerPressedEventArgs e)
{ {
if (!e.IsGestureRecognitionSkipped) if (!e.IsGestureRecognitionSkipped)

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

@ -91,12 +91,16 @@ namespace Avalonia.Input
internal void CaptureGestureRecognizer(GestureRecognizer? gestureRecognizer) internal void CaptureGestureRecognizer(GestureRecognizer? gestureRecognizer)
{ {
if (CapturedGestureRecognizer != gestureRecognizer) if (CapturedGestureRecognizer != gestureRecognizer)
{
CapturedGestureRecognizer?.PointerCaptureLostInternal(this); CapturedGestureRecognizer?.PointerCaptureLostInternal(this);
}
CapturedGestureRecognizer = gestureRecognizer;
if (gestureRecognizer != null) if (gestureRecognizer != null)
{
Capture(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); 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] [Fact]
public void Scrolling_Should_Start_After_Start_Distance_Is_Exceeded() 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); Down(target, source, position, modifiers);
Up(target, source, position, modifiers); Up(target, source, position, modifiers);
} }
public void Cancel()
{
_pointer.Capture(null);
_pointer.CaptureGestureRecognizer(null);
}
} }
} }

Loading…
Cancel
Save