@ -1,9 +1,13 @@
using System ;
using System.Collections.Generic ;
using Avalonia.Controls ;
using Avalonia.Input ;
using Avalonia.Input.GestureRecognizers ;
using Avalonia.Media ;
using Avalonia.Platform ;
using Avalonia.Threading ;
using Avalonia.UnitTests ;
using Moq ;
using Xunit ;
namespace Avalonia.Base.UnitTests.Input
@ -169,6 +173,242 @@ namespace Avalonia.Base.UnitTests.Input
Assert . False ( raised ) ;
}
[Fact]
public void Hold_Should_Be_Raised_After_Hold_Duration ( )
{
using var scope = AvaloniaLocator . EnterScope ( ) ;
var iSettingsMock = new Mock < IPlatformSettings > ( ) ;
iSettingsMock . Setup ( x = > x . HoldWaitDuration ) . Returns ( TimeSpan . FromMilliseconds ( 3 0 0 ) ) ;
iSettingsMock . Setup ( x = > x . GetTapSize ( It . IsAny < PointerType > ( ) ) ) . Returns ( new Size ( 1 6 , 1 6 ) ) ;
AvaloniaLocator . CurrentMutable . BindToSelf ( this )
. Bind < IPlatformSettings > ( ) . ToConstant ( iSettingsMock . Object ) ;
var scheduledTimers = new List < ( TimeSpan time , Action action ) > ( ) ;
using var app = UnitTestApplication . Start ( new TestServices (
threadingInterface : CreatePlatformThreadingInterface ( t = > scheduledTimers . Add ( t ) ) ) ) ;
Border border = new Border ( ) ;
Gestures . SetIsHoldWithMouseEnabled ( border , true ) ;
var decorator = new Decorator
{
Child = border
} ;
HoldingState holding = HoldingState . Cancelled ;
decorator . AddHandler ( Gestures . HoldingEvent , ( s , e ) = > holding = e . HoldingState ) ;
_ mouse . Down ( border ) ;
Assert . False ( holding ! = HoldingState . Cancelled ) ;
// Verify timer duration, but execute it immediately.
var timer = Assert . Single ( scheduledTimers ) ;
Assert . Equal ( iSettingsMock . Object . HoldWaitDuration , timer . time ) ;
timer . action ( ) ;
Assert . True ( holding = = HoldingState . Started ) ;
_ mouse . Up ( border ) ;
Assert . True ( holding = = HoldingState . Completed ) ;
}
[Fact]
public void Hold_Should_Not_Raised_When_Pointer_Released_Before_Timer ( )
{
using var scope = AvaloniaLocator . EnterScope ( ) ;
var iSettingsMock = new Mock < IPlatformSettings > ( ) ;
iSettingsMock . Setup ( x = > x . HoldWaitDuration ) . Returns ( TimeSpan . FromMilliseconds ( 3 0 0 ) ) ;
AvaloniaLocator . CurrentMutable . BindToSelf ( this )
. Bind < IPlatformSettings > ( ) . ToConstant ( iSettingsMock . Object ) ;
var scheduledTimers = new List < ( TimeSpan time , Action action ) > ( ) ;
using var app = UnitTestApplication . Start ( new TestServices (
threadingInterface : CreatePlatformThreadingInterface ( t = > scheduledTimers . Add ( t ) ) ) ) ;
Border border = new Border ( ) ;
Gestures . SetIsHoldWithMouseEnabled ( border , true ) ;
var decorator = new Decorator
{
Child = border
} ;
var raised = false ;
decorator . AddHandler ( Gestures . HoldingEvent , ( s , e ) = > raised = e . HoldingState = = HoldingState . Started ) ;
_ mouse . Down ( border ) ;
Assert . False ( raised ) ;
_ mouse . Up ( border ) ;
Assert . False ( raised ) ;
// Verify timer duration, but execute it immediately.
var timer = Assert . Single ( scheduledTimers ) ;
Assert . Equal ( iSettingsMock . Object . HoldWaitDuration , timer . time ) ;
timer . action ( ) ;
Assert . False ( raised ) ;
}
[Fact]
public void Hold_Should_Not_Raised_When_Pointer_Is_Moved_Before_Timer ( )
{
using var scope = AvaloniaLocator . EnterScope ( ) ;
var iSettingsMock = new Mock < IPlatformSettings > ( ) ;
iSettingsMock . Setup ( x = > x . HoldWaitDuration ) . Returns ( TimeSpan . FromMilliseconds ( 3 0 0 ) ) ;
AvaloniaLocator . CurrentMutable . BindToSelf ( this )
. Bind < IPlatformSettings > ( ) . ToConstant ( iSettingsMock . Object ) ;
var scheduledTimers = new List < ( TimeSpan time , Action action ) > ( ) ;
using var app = UnitTestApplication . Start ( new TestServices (
threadingInterface : CreatePlatformThreadingInterface ( t = > scheduledTimers . Add ( t ) ) ) ) ;
Border border = new Border ( ) ;
Gestures . SetIsHoldWithMouseEnabled ( border , true ) ;
var decorator = new Decorator
{
Child = border
} ;
var raised = false ;
decorator . AddHandler ( Gestures . HoldingEvent , ( s , e ) = > raised = e . HoldingState = = HoldingState . Completed ) ;
_ mouse . Down ( border ) ;
Assert . False ( raised ) ;
_ mouse . Move ( border , position : new Point ( 2 0 , 2 0 ) ) ;
Assert . False ( raised ) ;
// Verify timer duration, but execute it immediately.
var timer = Assert . Single ( scheduledTimers ) ;
Assert . Equal ( iSettingsMock . Object . HoldWaitDuration , timer . time ) ;
timer . action ( ) ;
Assert . False ( raised ) ;
}
[Fact]
public void Hold_Should_Be_Cancelled_When_Second_Contact_Is_Detected ( )
{
using var scope = AvaloniaLocator . EnterScope ( ) ;
var iSettingsMock = new Mock < IPlatformSettings > ( ) ;
iSettingsMock . Setup ( x = > x . HoldWaitDuration ) . Returns ( TimeSpan . FromMilliseconds ( 3 0 0 ) ) ;
AvaloniaLocator . CurrentMutable . BindToSelf ( this )
. Bind < IPlatformSettings > ( ) . ToConstant ( iSettingsMock . Object ) ;
var scheduledTimers = new List < ( TimeSpan time , Action action ) > ( ) ;
using var app = UnitTestApplication . Start ( new TestServices (
threadingInterface : CreatePlatformThreadingInterface ( t = > scheduledTimers . Add ( t ) ) ) ) ;
Border border = new Border ( ) ;
Gestures . SetIsHoldWithMouseEnabled ( border , true ) ;
var decorator = new Decorator
{
Child = border
} ;
var cancelled = false ;
decorator . AddHandler ( Gestures . HoldingEvent , ( s , e ) = > cancelled = e . HoldingState = = HoldingState . Cancelled ) ;
_ mouse . Down ( border ) ;
Assert . False ( cancelled ) ;
var timer = Assert . Single ( scheduledTimers ) ;
Assert . Equal ( iSettingsMock . Object . HoldWaitDuration , timer . time ) ;
timer . action ( ) ;
var secondMouse = new MouseTestHelper ( ) ;
secondMouse . Down ( border ) ;
Assert . True ( cancelled ) ;
}
[Fact]
public void Hold_Should_Be_Cancelled_When_Pointer_Moves_Too_Far ( )
{
using var scope = AvaloniaLocator . EnterScope ( ) ;
var iSettingsMock = new Mock < IPlatformSettings > ( ) ;
iSettingsMock . Setup ( x = > x . HoldWaitDuration ) . Returns ( TimeSpan . FromMilliseconds ( 3 0 0 ) ) ;
iSettingsMock . Setup ( x = > x . GetTapSize ( It . IsAny < PointerType > ( ) ) ) . Returns ( new Size ( 1 6 , 1 6 ) ) ;
AvaloniaLocator . CurrentMutable . BindToSelf ( this )
. Bind < IPlatformSettings > ( ) . ToConstant ( iSettingsMock . Object ) ;
var scheduledTimers = new List < ( TimeSpan time , Action action ) > ( ) ;
using var app = UnitTestApplication . Start ( new TestServices (
threadingInterface : CreatePlatformThreadingInterface ( t = > scheduledTimers . Add ( t ) ) ) ) ;
Border border = new Border ( ) ;
Gestures . SetIsHoldWithMouseEnabled ( border , true ) ;
var decorator = new Decorator
{
Child = border
} ;
var cancelled = false ;
decorator . AddHandler ( Gestures . HoldingEvent , ( s , e ) = > cancelled = e . HoldingState = = HoldingState . Cancelled ) ;
_ mouse . Down ( border ) ;
var timer = Assert . Single ( scheduledTimers ) ;
Assert . Equal ( iSettingsMock . Object . HoldWaitDuration , timer . time ) ;
timer . action ( ) ;
_ mouse . Move ( border , position : new Point ( 3 , 3 ) ) ;
Assert . False ( cancelled ) ;
_ mouse . Move ( border , position : new Point ( 2 0 , 2 0 ) ) ;
Assert . True ( cancelled ) ;
}
[Fact]
public void Hold_Should_Not_Be_Raised_For_Multiple_Contacts ( )
{
using var scope = AvaloniaLocator . EnterScope ( ) ;
var iSettingsMock = new Mock < IPlatformSettings > ( ) ;
iSettingsMock . Setup ( x = > x . HoldWaitDuration ) . Returns ( TimeSpan . FromMilliseconds ( 3 0 0 ) ) ;
AvaloniaLocator . CurrentMutable . BindToSelf ( this )
. Bind < IPlatformSettings > ( ) . ToConstant ( iSettingsMock . Object ) ;
var scheduledTimers = new List < ( TimeSpan time , Action action ) > ( ) ;
using var app = UnitTestApplication . Start ( new TestServices (
threadingInterface : CreatePlatformThreadingInterface ( t = > scheduledTimers . Add ( t ) ) ) ) ;
Border border = new Border ( ) ;
Gestures . SetIsHoldWithMouseEnabled ( border , true ) ;
var decorator = new Decorator
{
Child = border
} ;
var raised = false ;
decorator . AddHandler ( Gestures . HoldingEvent , ( s , e ) = > raised = e . HoldingState = = HoldingState . Completed ) ;
var secondMouse = new MouseTestHelper ( ) ;
_ mouse . Down ( border , MouseButton . Left ) ;
// Verify timer duration, but execute it immediately.
var timer = Assert . Single ( scheduledTimers ) ;
Assert . Equal ( iSettingsMock . Object . HoldWaitDuration , timer . time ) ;
timer . action ( ) ;
secondMouse . Down ( border , MouseButton . Left ) ;
Assert . False ( raised ) ;
}
private static IPlatformThreadingInterface CreatePlatformThreadingInterface ( Action < ( TimeSpan , Action ) > callback )
{
var threadingInterface = new Mock < IPlatformThreadingInterface > ( ) ;
threadingInterface . SetupGet ( p = > p . CurrentThreadIsLoopThread ) . Returns ( true ) ;
threadingInterface . Setup ( p = > p
. StartTimer ( It . IsAny < DispatcherPriority > ( ) , It . IsAny < TimeSpan > ( ) , It . IsAny < Action > ( ) ) )
. Callback < DispatcherPriority , TimeSpan , Action > ( ( _ , t , a ) = > callback ( ( t , a ) ) ) ;
return threadingInterface . Object ;
}
private static void AddHandlers (
Decorator decorator ,
Border border ,