Browse Source

Merge branch 'master' into fix/ButtonSpinnerPointerWheel

pull/7252/head
Max Katz 5 years ago
committed by GitHub
parent
commit
7199cc2fce
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/Avalonia/Avalonia.csproj
  2. 33
      samples/ControlCatalog/App.xaml.cs
  3. 42
      samples/ControlCatalog/MainView.xaml.cs
  4. 2
      src/Avalonia.Animation/Avalonia.Animation.csproj
  5. 2
      src/Avalonia.Base/Avalonia.Base.csproj
  6. 2
      src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
  7. 2
      src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
  8. 2
      src/Avalonia.Controls/Avalonia.Controls.csproj
  9. 2
      src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj
  10. 2
      src/Avalonia.Desktop/Avalonia.Desktop.csproj
  11. 2
      src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj
  12. 2
      src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
  13. 2
      src/Avalonia.Dialogs/Avalonia.Dialogs.csproj
  14. 2
      src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj
  15. 2
      src/Avalonia.Headless.Vnc/Avalonia.Headless.Vnc.csproj
  16. 2
      src/Avalonia.Headless/Avalonia.Headless.csproj
  17. 2
      src/Avalonia.Input/Avalonia.Input.csproj
  18. 2
      src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs
  19. 2
      src/Avalonia.Input/TouchDevice.cs
  20. 2
      src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
  21. 2
      src/Avalonia.Layout/Avalonia.Layout.csproj
  22. 2
      src/Avalonia.Native/Avalonia.Native.csproj
  23. 2
      src/Avalonia.OpenGL/Avalonia.OpenGL.csproj
  24. 2
      src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
  25. 2
      src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj
  26. 2
      src/Avalonia.Styling/Avalonia.Styling.csproj
  27. 2
      src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
  28. 2
      src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj
  29. 96
      src/Avalonia.Themes.Fluent/FluentTheme.cs
  30. 2
      src/Avalonia.Visuals/Avalonia.Visuals.csproj
  31. 4
      src/Avalonia.Visuals/Media/TextFormatting/Unicode/LineBreakEnumerator.cs
  32. 2
      src/Avalonia.X11/Avalonia.X11.csproj
  33. 2
      src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj
  34. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj
  35. 2
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  36. 2
      src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
  37. 2
      src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
  38. 2
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  39. 2
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  40. 346
      tests/Avalonia.Input.UnitTests/TouchDeviceTests.cs

2
packages/Avalonia/Avalonia.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net461;netcoreapp2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0;net461;netcoreapp2.0</TargetFrameworks>
<PackageId>Avalonia</PackageId> <PackageId>Avalonia</PackageId>
</PropertyGroup> </PropertyGroup>

33
samples/ControlCatalog/App.xaml.cs

@ -5,6 +5,7 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling; using Avalonia.Markup.Xaml.Styling;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.Themes.Fluent;
using ControlCatalog.ViewModels; using ControlCatalog.ViewModels;
namespace ControlCatalog namespace ControlCatalog
@ -16,33 +17,17 @@ namespace ControlCatalog
DataContext = new ApplicationViewModel(); DataContext = new ApplicationViewModel();
} }
private static readonly StyleInclude DataGridFluent = new StyleInclude(new Uri("avares://ControlCatalog/Styles")) public static readonly StyleInclude DataGridFluent = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
{ {
Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml") Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml")
}; };
private static readonly StyleInclude DataGridDefault = new StyleInclude(new Uri("avares://ControlCatalog/Styles")) public static readonly StyleInclude DataGridDefault = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
{ {
Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Default.xaml") Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Default.xaml")
}; };
public static Styles FluentDark = new Styles public static FluentTheme Fluent = new FluentTheme(new Uri("avares://ControlCatalog/Styles"));
{
new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
{
Source = new Uri("avares://Avalonia.Themes.Fluent/FluentDark.xaml")
},
DataGridFluent
};
public static Styles FluentLight = new Styles
{
new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
{
Source = new Uri("avares://Avalonia.Themes.Fluent/FluentLight.xaml")
},
DataGridFluent
};
public static Styles DefaultLight = new Styles public static Styles DefaultLight = new Styles
{ {
@ -65,8 +50,7 @@ namespace ControlCatalog
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog")) new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{ {
Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml") Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml")
}, }
DataGridDefault
}; };
public static Styles DefaultDark = new Styles public static Styles DefaultDark = new Styles
@ -90,14 +74,13 @@ namespace ControlCatalog
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog")) new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{ {
Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml") Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml")
}, }
DataGridDefault
}; };
public override void Initialize() public override void Initialize()
{ {
Styles.Insert(0, FluentLight); Styles.Insert(0, Fluent);
Styles.Insert(1, DataGridFluent);
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }

42
samples/ControlCatalog/MainView.xaml.cs

@ -3,14 +3,12 @@ using System.Collections;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Markup.Xaml.XamlIl;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Immutable; using Avalonia.Media.Immutable;
using Avalonia.Platform; using Avalonia.Platform;
using ControlCatalog.Pages; using Avalonia.Themes.Fluent;
using ControlCatalog.Models; using ControlCatalog.Models;
using ControlCatalog.Pages;
namespace ControlCatalog namespace ControlCatalog
{ {
@ -43,14 +41,36 @@ namespace ControlCatalog
{ {
if (themes.SelectedItem is CatalogTheme theme) if (themes.SelectedItem is CatalogTheme theme)
{ {
Application.Current.Styles[0] = theme switch var themeStyle = Application.Current.Styles[0];
if (theme == CatalogTheme.FluentLight)
{
if (App.Fluent.Mode != FluentThemeMode.Light)
{
App.Fluent.Mode = FluentThemeMode.Light;
}
Application.Current.Styles[0] = App.Fluent;
Application.Current.Styles[1] = App.DataGridFluent;
}
else if (theme == CatalogTheme.FluentDark)
{
if (App.Fluent.Mode != FluentThemeMode.Dark)
{
App.Fluent.Mode = FluentThemeMode.Dark;
}
Application.Current.Styles[0] = App.Fluent;
Application.Current.Styles[1] = App.DataGridFluent;
}
else if (theme == CatalogTheme.DefaultLight)
{
Application.Current.Styles[0] = App.DefaultLight;
Application.Current.Styles[1] = App.DataGridDefault;
}
else if (theme == CatalogTheme.DefaultDark)
{ {
CatalogTheme.FluentLight => App.FluentLight, Application.Current.Styles[0] = App.DefaultDark;
CatalogTheme.FluentDark => App.FluentDark, Application.Current.Styles[1] = App.DataGridDefault;
CatalogTheme.DefaultLight => App.DefaultLight, }
CatalogTheme.DefaultDark => App.DefaultDark,
_ => Application.Current.Styles[0]
};
} }
}; };

2
src/Avalonia.Animation/Avalonia.Animation.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" /> <ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />

2
src/Avalonia.Base/Avalonia.Base.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AssemblyName>Avalonia.Base</AssemblyName> <AssemblyName>Avalonia.Base</AssemblyName>
<RootNamespace>Avalonia</RootNamespace> <RootNamespace>Avalonia</RootNamespace>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>

2
src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs

@ -180,7 +180,7 @@ namespace Avalonia.Utilities
{ {
var r = _data[c]; var r = _data[c];
if (r?.TryGetTarget(out var sub) == true) if (r?.TryGetTarget(out var sub) == true)
sub.OnEvent(sender, eventArgs); sub!.OnEvent(sender, eventArgs);
else else
needCompact = true; needCompact = true;
} }

2
src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<PackageId>Avalonia.Controls.DataGrid</PackageId> <PackageId>Avalonia.Controls.DataGrid</PackageId>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" /> <Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" />

2
src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<!-- WARNING! The designer support version number needs to be frozen <!-- WARNING! The designer support version number needs to be frozen
To allow projects that implement designer functionality to still To allow projects that implement designer functionality to still
work with newer versions of Avalonia. This version number only work with newer versions of Avalonia. This version number only

2
src/Avalonia.Desktop/Avalonia.Desktop.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<PackageId>Avalonia.Desktop</PackageId> <PackageId>Avalonia.Desktop</PackageId>
</PropertyGroup> </PropertyGroup>

2
src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;net461;netcoreapp2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<RootNamespace>Avalonia</RootNamespace> <RootNamespace>Avalonia</RootNamespace>
<PackageId>Avalonia.Diagnostics</PackageId> <PackageId>Avalonia.Diagnostics</PackageId>
</PropertyGroup> </PropertyGroup>

2
src/Avalonia.Dialogs/Avalonia.Dialogs.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
src/Avalonia.Headless.Vnc/Avalonia.Headless.Vnc.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
src/Avalonia.Headless/Avalonia.Headless.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
src/Avalonia.Input/Avalonia.Input.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" /> <Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" />

2
src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs

@ -71,7 +71,7 @@ namespace Avalonia.Input.GestureRecognizers
EndGesture(); EndGesture();
_tracking = e.Pointer; _tracking = e.Pointer;
_gestureId = ScrollGestureEventArgs.GetNextFreeId();; _gestureId = ScrollGestureEventArgs.GetNextFreeId();;
_trackedRootPoint = e.GetPosition(null); _trackedRootPoint = e.GetPosition(_target);
} }
} }

2
src/Avalonia.Input/TouchDevice.cs

@ -61,7 +61,7 @@ namespace Avalonia.Input
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>(); var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>();
if (settings == null) if (settings == null)
{ {
throw new Exception("IPlatformSettings can not be null"); throw new Exception("IPlatformSettings can not be null.");
} }
if (!_lastClickRect.Contains(args.Position) if (!_lastClickRect.Contains(args.Position)
|| ev.Timestamp - _lastClickTime > settings.DoubleClickTime.TotalMilliseconds) || ev.Timestamp - _lastClickTime > settings.DoubleClickTime.TotalMilliseconds)

2
src/Avalonia.Interactivity/Avalonia.Interactivity.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" /> <ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" />

2
src/Avalonia.Layout/Avalonia.Layout.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" /> <ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" />

2
src/Avalonia.Native/Avalonia.Native.csproj

@ -4,7 +4,7 @@
<PackAvaloniaNative Condition="'$(PackAvaloniaNative)' == ''">$([MSBuild]::IsOSPlatform(OSX))</PackAvaloniaNative> <PackAvaloniaNative Condition="'$(PackAvaloniaNative)' == ''">$([MSBuild]::IsOSPlatform(OSX))</PackAvaloniaNative>
<IsPackable>$(PackAvaloniaNative)</IsPackable> <IsPackable>$(PackAvaloniaNative)</IsPackable>
<IsPackable Condition="'$([MSBuild]::IsOSPlatform(OSX))' == 'True'">true</IsPackable> <IsPackable Condition="'$([MSBuild]::IsOSPlatform(OSX))' == 'True'">true</IsPackable>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>

2
src/Avalonia.OpenGL/Avalonia.OpenGL.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>

2
src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<PackageId>Avalonia.ReactiveUI</PackageId> <PackageId>Avalonia.ReactiveUI</PackageId>
<SignAssembly>false</SignAssembly> <SignAssembly>false</SignAssembly>
</PropertyGroup> </PropertyGroup>

2
src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<DefineConstants>AVALONIA_REMOTE_PROTOCOL;$(DefineConstants)</DefineConstants> <DefineConstants>AVALONIA_REMOTE_PROTOCOL;$(DefineConstants)</DefineConstants>
<SignAssembly>true</SignAssembly> <SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile>

2
src/Avalonia.Styling/Avalonia.Styling.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AssemblyName>Avalonia.Styling</AssemblyName> <AssemblyName>Avalonia.Styling</AssemblyName>
<RootNamespace>Avalonia</RootNamespace> <RootNamespace>Avalonia</RootNamespace>
</PropertyGroup> </PropertyGroup>

2
src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" /> <ProjectReference Include="..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />

2
src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" /> <ProjectReference Include="..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />

96
src/Avalonia.Themes.Fluent/FluentTheme.cs

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Styling; using Avalonia.Styling;
#nullable enable #nullable enable
@ -17,11 +18,14 @@ namespace Avalonia.Themes.Fluent
/// <summary> /// <summary>
/// Includes the fluent theme in an application. /// Includes the fluent theme in an application.
/// </summary> /// </summary>
public class FluentTheme : IStyle, IResourceProvider public class FluentTheme : AvaloniaObject, IStyle, IResourceProvider
{ {
private readonly Uri _baseUri; private readonly Uri _baseUri;
private IStyle[]? _loaded; private Styles _fluentDark = new();
private Styles _fluentLight = new();
private Styles _sharedStyles = new();
private bool _isLoading; private bool _isLoading;
private IStyle? _loaded;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FluentTheme"/> class. /// Initializes a new instance of the <see cref="FluentTheme"/> class.
@ -30,6 +34,7 @@ namespace Avalonia.Themes.Fluent
public FluentTheme(Uri baseUri) public FluentTheme(Uri baseUri)
{ {
_baseUri = baseUri; _baseUri = baseUri;
InitStyles(baseUri);
} }
/// <summary> /// <summary>
@ -39,12 +44,37 @@ namespace Avalonia.Themes.Fluent
public FluentTheme(IServiceProvider serviceProvider) public FluentTheme(IServiceProvider serviceProvider)
{ {
_baseUri = ((IUriContext)serviceProvider.GetService(typeof(IUriContext))).BaseUri; _baseUri = ((IUriContext)serviceProvider.GetService(typeof(IUriContext))).BaseUri;
InitStyles(_baseUri);
} }
public static readonly StyledProperty<FluentThemeMode> ModeProperty =
AvaloniaProperty.Register<FluentTheme, FluentThemeMode>(nameof(Mode));
/// <summary> /// <summary>
/// Gets or sets the mode of the fluent theme (light, dark). /// Gets or sets the mode of the fluent theme (light, dark).
/// </summary> /// </summary>
public FluentThemeMode Mode { get; set; } public FluentThemeMode Mode
{
get => GetValue(ModeProperty);
set => SetValue(ModeProperty, value);
}
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == ModeProperty)
{
if (Mode == FluentThemeMode.Dark)
{
(Loaded as Styles)![1] = _fluentDark[0];
(Loaded as Styles)![2] = _fluentDark[1];
}
else
{
(Loaded as Styles)![1] = _fluentLight[0];
(Loaded as Styles)![2] = _fluentLight[1];
}
}
}
public IResourceHost? Owner => (Loaded as IResourceProvider)?.Owner; public IResourceHost? Owner => (Loaded as IResourceProvider)?.Owner;
@ -58,18 +88,25 @@ namespace Avalonia.Themes.Fluent
if (_loaded == null) if (_loaded == null)
{ {
_isLoading = true; _isLoading = true;
var loaded = (IStyle)AvaloniaXamlLoader.Load(GetUri(), _baseUri);
_loaded = new[] { loaded }; if (Mode == FluentThemeMode.Light)
{
_loaded = new Styles() { _sharedStyles , _fluentLight[0], _fluentLight[1] };
}
else if (Mode == FluentThemeMode.Dark)
{
_loaded = new Styles() { _sharedStyles, _fluentDark[0], _fluentDark[1] };
}
_isLoading = false; _isLoading = false;
} }
return _loaded?[0]!; return _loaded!;
} }
} }
bool IResourceNode.HasResources => (Loaded as IResourceProvider)?.HasResources ?? false; bool IResourceNode.HasResources => (Loaded as IResourceProvider)?.HasResources ?? false;
IReadOnlyList<IStyle> IStyle.Children => _loaded ?? Array.Empty<IStyle>(); IReadOnlyList<IStyle> IStyle.Children => _loaded?.Children ?? Array.Empty<IStyle>();
public event EventHandler OwnerChanged public event EventHandler OwnerChanged
{ {
@ -105,10 +142,47 @@ namespace Avalonia.Themes.Fluent
void IResourceProvider.AddOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.AddOwner(owner); void IResourceProvider.AddOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.AddOwner(owner);
void IResourceProvider.RemoveOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.RemoveOwner(owner); void IResourceProvider.RemoveOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.RemoveOwner(owner);
private Uri GetUri() => Mode switch private void InitStyles(Uri baseUri)
{ {
FluentThemeMode.Dark => new Uri("avares://Avalonia.Themes.Fluent/FluentDark.xaml", UriKind.Absolute), _sharedStyles = new Styles
_ => new Uri("avares://Avalonia.Themes.Fluent/FluentLight.xaml", UriKind.Absolute), {
}; new StyleInclude(baseUri)
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/AccentColors.xaml")
},
new StyleInclude(baseUri)
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/Base.xaml")
},
new StyleInclude(baseUri)
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Controls/FluentControls.xaml")
}
};
_fluentLight = new Styles
{
new StyleInclude(baseUri)
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseLight.xaml")
},
new StyleInclude(baseUri)
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml")
}
};
_fluentDark = new Styles
{
new StyleInclude(baseUri)
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseDark.xaml")
},
new StyleInclude(baseUri)
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml")
}
};
}
} }
} }

2
src/Avalonia.Visuals/Avalonia.Visuals.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<RootNamespace>Avalonia</RootNamespace> <RootNamespace>Avalonia</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>

4
src/Avalonia.Visuals/Media/TextFormatting/Unicode/LineBreakEnumerator.cs

@ -80,12 +80,12 @@ namespace Avalonia.Media.TextFormatting.Unicode
} }
} }
var shouldBreak = GetSimpleBreak() ?? (bool?)GetPairTableBreak(lastClass); var shouldBreak = GetSimpleBreak() ?? GetPairTableBreak(lastClass);
// Rule LB8a // Rule LB8a
_lb8a = _nextClass == LineBreakClass.ZWJ; _lb8a = _nextClass == LineBreakClass.ZWJ;
if (shouldBreak.Value) if (shouldBreak)
{ {
Current = new LineBreak(FindPriorNonWhitespace(_lastPosition), _lastPosition); Current = new LineBreak(FindPriorNonWhitespace(_lastPosition), _lastPosition);
return true; return true;

2
src/Avalonia.X11/Avalonia.X11.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PackageId>Avalonia.X11</PackageId> <PackageId>Avalonia.X11</PackageId>
</PropertyGroup> </PropertyGroup>

2
src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PackageId>Avalonia.LinuxFramebuffer</PackageId> <PackageId>Avalonia.LinuxFramebuffer</PackageId>
</PropertyGroup> </PropertyGroup>

2
src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<PackageId>Avalonia.Markup.Xaml.Loader</PackageId> <PackageId>Avalonia.Markup.Xaml.Loader</PackageId>
<DefineConstants>$(DefineConstants);XAMLX_INTERNAL</DefineConstants> <DefineConstants>$(DefineConstants);XAMLX_INTERNAL</DefineConstants>

2
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<DefineConstants>$(DefineConstants);PCL;NETSTANDARD;NETSTANDARD2_0;HAS_TYPE_CONVERTER;HAS_CUSTOM_ATTRIBUTE_PROVIDER;XAMLX_INTERNAL</DefineConstants> <DefineConstants>$(DefineConstants);PCL;NETSTANDARD;NETSTANDARD2_0;HAS_TYPE_CONVERTER;HAS_CUSTOM_ATTRIBUTE_PROVIDER;XAMLX_INTERNAL</DefineConstants>
<UseCecil>false</UseCecil> <UseCecil>false</UseCecil>
<DefineConstants Condition="$(UseCecil) == true">$(DefineConstants);RUNTIME_XAML_CECIL</DefineConstants> <DefineConstants Condition="$(UseCecil) == true">$(DefineConstants);RUNTIME_XAML_CECIL</DefineConstants>

2
src/Markup/Avalonia.Markup/Avalonia.Markup.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<RootNamespace>Avalonia</RootNamespace> <RootNamespace>Avalonia</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
src/Skia/Avalonia.Skia/Avalonia.Skia.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<RootNamespace>Avalonia.Skia</RootNamespace> <RootNamespace>Avalonia.Skia</RootNamespace>
<AssemblyName>Avalonia.Skia</AssemblyName> <AssemblyName>Avalonia.Skia</AssemblyName>
<PackageId>Avalonia.Skia</PackageId> <PackageId>Avalonia.Skia</PackageId>

2
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PackageId>Avalonia.Direct2D1</PackageId> <PackageId>Avalonia.Direct2D1</PackageId>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>

2
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PackageId>Avalonia.Win32</PackageId> <PackageId>Avalonia.Win32</PackageId>
</PropertyGroup> </PropertyGroup>

346
tests/Avalonia.Input.UnitTests/TouchDeviceTests.cs

@ -12,56 +12,47 @@ namespace Avalonia.Input.UnitTests
[Fact] [Fact]
public void Tapped_Event_Is_Fired_With_Touch() public void Tapped_Event_Is_Fired_With_Touch()
{ {
using (UnitTestApplication.Start( using var app = UnitTestApp(new TimeSpan(200));
new TestServices(inputManager: new InputManager()))) var root = new TestRoot();
var touchDevice = new TouchDevice();
var isTapped = false;
var executedTimes = 0;
root.Tapped += (a, e) =>
{ {
var root = new TestRoot(); isTapped = true;
var touchDevice = new TouchDevice(); executedTimes++;
};
TapOnce(InputManager.Instance, touchDevice, root);
Assert.True(isTapped);
Assert.Equal(1, executedTimes);
var isTapped = false;
var executedTimes = 0;
root.Tapped += (a, e) =>
{
isTapped = true;
executedTimes++;
};
TapOnce(InputManager.Instance, touchDevice, root);
Assert.True(isTapped);
Assert.Equal(1, executedTimes);
}
} }
[Fact] [Fact]
public void DoubleTapped_Event_Is_Fired_With_Touch() public void DoubleTapped_Event_Is_Fired_With_Touch()
{ {
var platformSettingsMock = new Mock<IPlatformSettings>(); using var app = UnitTestApp(new TimeSpan(200));
platformSettingsMock.Setup(x => x.DoubleClickTime).Returns(new TimeSpan(200)); var root = new TestRoot();
AvaloniaLocator.CurrentMutable.BindToSelf(this) var touchDevice = new TouchDevice();
.Bind<IPlatformSettings>().ToConstant(platformSettingsMock.Object);
using (UnitTestApplication.Start( var isDoubleTapped = false;
new TestServices(inputManager: new InputManager()))) var doubleTappedExecutedTimes = 0;
var tappedExecutedTimes = 0;
root.DoubleTapped += (a, e) =>
{ {
var root = new TestRoot(); isDoubleTapped = true;
var touchDevice = new TouchDevice(); doubleTappedExecutedTimes++;
};
var isDoubleTapped = false; root.Tapped += (a, e) =>
var doubleTappedExecutedTimes = 0; {
var tappedExecutedTimes = 0; tappedExecutedTimes++;
root.DoubleTapped += (a, e) => };
{ TapOnce(InputManager.Instance, touchDevice, root);
isDoubleTapped = true; TapOnce(InputManager.Instance, touchDevice, root, touchPointId: 1);
doubleTappedExecutedTimes++; Assert.Equal(1, tappedExecutedTimes);
}; Assert.True(isDoubleTapped);
root.Tapped += (a, e) => Assert.Equal(1, doubleTappedExecutedTimes);
{
tappedExecutedTimes++;
};
TapOnce(InputManager.Instance, touchDevice, root);
TapOnce(InputManager.Instance, touchDevice, root, touchPointId: 1);
Assert.Equal(1, tappedExecutedTimes);
Assert.True(isDoubleTapped);
Assert.Equal(1, doubleTappedExecutedTimes);
}
} }
[Theory] [Theory]
@ -72,173 +63,158 @@ namespace Avalonia.Input.UnitTests
[InlineData(5)] [InlineData(5)]
public void PointerPressed_Counts_Clicks_Correctly(int clickCount) public void PointerPressed_Counts_Clicks_Correctly(int clickCount)
{ {
var platformSettingsMock = new Mock<IPlatformSettings>(); using var app = UnitTestApp(new TimeSpan(200));
platformSettingsMock.Setup(x => x.DoubleClickTime).Returns(new TimeSpan(200)); var root = new TestRoot();
AvaloniaLocator.CurrentMutable.BindToSelf(this) var touchDevice = new TouchDevice();
.Bind<IPlatformSettings>().ToConstant(platformSettingsMock.Object);
using (UnitTestApplication.Start(
new TestServices(inputManager: new InputManager())))
{
var root = new TestRoot();
var touchDevice = new TouchDevice();
var pointerPressedExecutedTimes = 0; var pointerPressedExecutedTimes = 0;
var pointerPressedClicks = 0; var pointerPressedClicks = 0;
root.PointerPressed += (a, e) => root.PointerPressed += (a, e) =>
{ {
pointerPressedClicks = e.ClickCount; pointerPressedClicks = e.ClickCount;
pointerPressedExecutedTimes++; pointerPressedExecutedTimes++;
}; };
for (int i = 0; i < clickCount; i++) for (int i = 0; i < clickCount; i++)
{ {
TapOnce(InputManager.Instance, touchDevice, root, touchPointId: i); TapOnce(InputManager.Instance, touchDevice, root, touchPointId: i);
}
Assert.Equal(clickCount, pointerPressedExecutedTimes);
Assert.Equal(pointerPressedClicks, clickCount);
} }
Assert.Equal(clickCount, pointerPressedExecutedTimes);
Assert.Equal(pointerPressedClicks, clickCount);
} }
[Fact] [Fact]
public void DoubleTapped_Not_Fired_When_Click_Too_Late() public void DoubleTapped_Not_Fired_When_Click_Too_Late()
{ {
var platformSettingsMock = new Mock<IPlatformSettings>(); using var app = UnitTestApp(new TimeSpan(0, 0, 0, 0, 20));
platformSettingsMock.Setup(x => x.DoubleClickTime).Returns(new TimeSpan(0, 0, 0, 0, 20)); var root = new TestRoot();
AvaloniaLocator.CurrentMutable.BindToSelf(this) var touchDevice = new TouchDevice();
.Bind<IPlatformSettings>().ToConstant(platformSettingsMock.Object);
using (UnitTestApplication.Start( var isDoubleTapped = false;
new TestServices(inputManager: new InputManager()))) var doubleTappedExecutedTimes = 0;
var tappedExecutedTimes = 0;
root.DoubleTapped += (a, e) =>
{ {
var root = new TestRoot(); isDoubleTapped = true;
var touchDevice = new TouchDevice(); doubleTappedExecutedTimes++;
};
root.Tapped += (a, e) =>
{
tappedExecutedTimes++;
};
TapOnce(InputManager.Instance, touchDevice, root);
TapOnce(InputManager.Instance, touchDevice, root, 21, 1);
Assert.Equal(2, tappedExecutedTimes);
Assert.False(isDoubleTapped);
Assert.Equal(0, doubleTappedExecutedTimes);
var isDoubleTapped = false;
var doubleTappedExecutedTimes = 0;
var tappedExecutedTimes = 0;
root.DoubleTapped += (a, e) =>
{
isDoubleTapped = true;
doubleTappedExecutedTimes++;
};
root.Tapped += (a, e) =>
{
tappedExecutedTimes++;
};
TapOnce(InputManager.Instance, touchDevice, root);
TapOnce(InputManager.Instance, touchDevice, root, 21, 1);
Assert.Equal(2, tappedExecutedTimes);
Assert.False(isDoubleTapped);
Assert.Equal(0, doubleTappedExecutedTimes);
}
} }
[Fact] [Fact]
public void DoubleTapped_Not_Fired_When_Second_Click_Is_From_Different_Touch_Contact() public void DoubleTapped_Not_Fired_When_Second_Click_Is_From_Different_Touch_Contact()
{ {
var tmp = new Mock<IPlatformSettings>(); using var app = UnitTestApp(new TimeSpan(200));
tmp.Setup(x => x.DoubleClickTime).Returns(new TimeSpan(200)); var root = new TestRoot();
AvaloniaLocator.CurrentMutable.BindToSelf(this) var touchDevice = new TouchDevice();
.Bind<IPlatformSettings>().ToConstant(tmp.Object);
using (UnitTestApplication.Start( var isDoubleTapped = false;
new TestServices(inputManager: new InputManager()))) var doubleTappedExecutedTimes = 0;
var tappedExecutedTimes = 0;
root.DoubleTapped += (a, e) =>
{ {
var root = new TestRoot(); isDoubleTapped = true;
var touchDevice = new TouchDevice(); doubleTappedExecutedTimes++;
};
var isDoubleTapped = false; root.Tapped += (a, e) =>
var doubleTappedExecutedTimes = 0; {
var tappedExecutedTimes = 0; tappedExecutedTimes++;
root.DoubleTapped += (a, e) => };
{ SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchBegin, 0, 1);
isDoubleTapped = true; SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchEnd, 0, 1);
doubleTappedExecutedTimes++; Assert.Equal(2, tappedExecutedTimes);
}; Assert.False(isDoubleTapped);
root.Tapped += (a, e) => Assert.Equal(0, doubleTappedExecutedTimes);
{
tappedExecutedTimes++;
};
SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchBegin, 0, 1);
SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchEnd, 0, 1);
Assert.Equal(2, tappedExecutedTimes);
Assert.False(isDoubleTapped);
Assert.Equal(0, doubleTappedExecutedTimes);
}
} }
[Fact] [Fact]
public void Click_Counting_Should_Work_Correctly_With_Few_Touch_Contacts() public void Click_Counting_Should_Work_Correctly_With_Few_Touch_Contacts()
{ {
var tmp = new Mock<IPlatformSettings>(); using var app = UnitTestApp(new TimeSpan(200));
tmp.Setup(x => x.DoubleClickTime).Returns(new TimeSpan(200));
AvaloniaLocator.CurrentMutable.BindToSelf(this)
.Bind<IPlatformSettings>().ToConstant(tmp.Object);
using (UnitTestApplication.Start(
new TestServices(inputManager: new InputManager())))
{
var root = new TestRoot();
var touchDevice = new TouchDevice();
var pointerPressedExecutedTimes = 0; var root = new TestRoot();
var tappedExecutedTimes = 0; var touchDevice = new TouchDevice();
var isDoubleTapped = false;
var doubleTappedExecutedTimes = 0; var pointerPressedExecutedTimes = 0;
root.PointerPressed += (a, e) => var tappedExecutedTimes = 0;
{ var isDoubleTapped = false;
pointerPressedExecutedTimes++; var doubleTappedExecutedTimes = 0;
switch (pointerPressedExecutedTimes) root.PointerPressed += (a, e) =>
{ {
case <= 2: pointerPressedExecutedTimes++;
Assert.True(e.ClickCount == 1); switch (pointerPressedExecutedTimes)
break;
case 3:
Assert.True(e.ClickCount == 2);
break;
case 4:
Assert.True(e.ClickCount == 3);
break;
case 5:
Assert.True(e.ClickCount == 4);
break;
case 6:
Assert.True(e.ClickCount == 5);
break;
case 7:
Assert.True(e.ClickCount == 1);
break;
case 8:
Assert.True(e.ClickCount == 1);
break;
case 9:
Assert.True(e.ClickCount == 2);
break;
default:
break;
}
};
root.DoubleTapped += (a, e) =>
{
isDoubleTapped = true;
doubleTappedExecutedTimes++;
};
root.Tapped += (a, e) =>
{ {
tappedExecutedTimes++; case <= 2:
}; Assert.True(e.ClickCount == 1);
SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchBegin, 0, 1); break;
SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchEnd, 0, 1); case 3:
TapOnce(InputManager.Instance, touchDevice, root, touchPointId: 2); Assert.True(e.ClickCount == 2);
TapOnce(InputManager.Instance, touchDevice, root, touchPointId: 3); break;
TapOnce(InputManager.Instance, touchDevice, root, touchPointId: 4); case 4:
SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchBegin, 5, 6, 7); Assert.True(e.ClickCount == 3);
SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchEnd, 5, 6, 7); break;
TapOnce(InputManager.Instance, touchDevice, root, touchPointId: 8); case 5:
Assert.Equal(6, tappedExecutedTimes); Assert.True(e.ClickCount == 4);
Assert.Equal(9, pointerPressedExecutedTimes); break;
Assert.True(isDoubleTapped); case 6:
Assert.Equal(3, doubleTappedExecutedTimes); Assert.True(e.ClickCount == 5);
break;
case 7:
Assert.True(e.ClickCount == 1);
break;
case 8:
Assert.True(e.ClickCount == 1);
break;
case 9:
Assert.True(e.ClickCount == 2);
break;
default:
break;
}
};
root.DoubleTapped += (a, e) =>
{
isDoubleTapped = true;
doubleTappedExecutedTimes++;
};
root.Tapped += (a, e) =>
{
tappedExecutedTimes++;
};
SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchBegin, 0, 1);
SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchEnd, 0, 1);
TapOnce(InputManager.Instance, touchDevice, root, touchPointId: 2);
TapOnce(InputManager.Instance, touchDevice, root, touchPointId: 3);
TapOnce(InputManager.Instance, touchDevice, root, touchPointId: 4);
SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchBegin, 5, 6, 7);
SendXTouchContactsWithIds(InputManager.Instance, touchDevice, root, RawPointerEventType.TouchEnd, 5, 6, 7);
TapOnce(InputManager.Instance, touchDevice, root, touchPointId: 8);
Assert.Equal(6, tappedExecutedTimes);
Assert.Equal(9, pointerPressedExecutedTimes);
Assert.True(isDoubleTapped);
Assert.Equal(3, doubleTappedExecutedTimes);
}
} private IDisposable UnitTestApp(TimeSpan doubleClickTime = new TimeSpan())
{
var unitTestApp = UnitTestApplication.Start(
new TestServices(inputManager: new InputManager()));
var iSettingsMock = new Mock<IPlatformSettings>();
iSettingsMock.Setup(x => x.DoubleClickTime).Returns(doubleClickTime);
AvaloniaLocator.CurrentMutable.BindToSelf(this)
.Bind<IPlatformSettings>().ToConstant(iSettingsMock.Object);
return unitTestApp;
} }
private static void SendXTouchContactsWithIds(IInputManager inputManager, TouchDevice device, IInputRoot root, RawPointerEventType type, params long[] touchPointIds) private static void SendXTouchContactsWithIds(IInputManager inputManager, TouchDevice device, IInputRoot root, RawPointerEventType type, params long[] touchPointIds)
{ {
for (int i = 0; i < touchPointIds.Length; i++) for (int i = 0; i < touchPointIds.Length; i++)

Loading…
Cancel
Save