Browse Source

Merge branch 'master' into pr/11418

pull/11418/head
Steven Kirk 3 years ago
parent
commit
1aa1c17b16
  1. 5
      .ncrunch/AppWithoutLifetime.v3.ncrunchproject
  2. 5
      .ncrunch/Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject
  3. 5
      .ncrunch/Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject
  4. 11
      Avalonia.Desktop.slnf
  5. 3
      Avalonia.sln
  6. 2
      build/SharedVersion.props
  7. 6
      dirs.proj
  8. 2
      nukebuild/Build.cs
  9. 48
      nukebuild/RefAssemblyGenerator.cs
  10. 6
      nukebuild/_build.csproj
  11. 2
      packages/Avalonia/Avalonia.csproj
  12. 1
      packages/Avalonia/Avalonia.targets
  13. 26
      packages/Avalonia/AvaloniaPrivateApis.targets
  14. 7
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  15. 11
      samples/ControlCatalog.Desktop/Program.cs
  16. 1
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  17. 5
      samples/ControlCatalog/MainView.xaml.cs
  18. 4
      samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
  19. 2
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  20. 3
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
  21. 29
      samples/ControlCatalog/Pages/TabControlPage.xaml
  22. 2
      samples/GpuInterop/MainWindow.axaml.cs
  23. 2
      samples/IntegrationTestApp/MainWindow.axaml.cs
  24. 21
      samples/MobileSandbox.Desktop/MobileSandbox.Desktop.csproj
  25. 15
      samples/MobileSandbox/MobileSandbox.csproj
  26. 2
      samples/RenderDemo/MainWindow.xaml.cs
  27. 4
      samples/RenderDemo/Pages/AnimationsPage.xaml
  28. 15
      samples/RenderDemo/Pages/AnimationsPage.xaml.cs
  29. 12
      samples/RenderDemo/Pages/CustomAnimatorPage.xaml
  30. 6
      samples/RenderDemo/Pages/CustomStringAnimator.cs
  31. 3
      samples/RenderDemo/Pages/Transform3DPage.axaml
  32. 4
      samples/RenderDemo/Pages/TransitionsPage.xaml
  33. 15
      samples/RenderDemo/Pages/TransitionsPage.xaml.cs
  34. 1
      samples/Sandbox/Sandbox.csproj
  35. 4
      samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs
  36. 23
      samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs
  37. 33
      samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml
  38. 52
      samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs
  39. 9
      samples/interop/WindowsInteropTest/Program.cs
  40. 76
      samples/interop/WindowsInteropTest/SelectorForm.Designer.cs
  41. 30
      samples/interop/WindowsInteropTest/SelectorForm.cs
  42. 120
      samples/interop/WindowsInteropTest/SelectorForm.resx
  43. 6
      samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
  44. 7
      src/Android/Avalonia.Android/AndroidPlatform.cs
  45. 4
      src/Android/Avalonia.Android/AvaloniaView.cs
  46. 112
      src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs
  47. 2
      src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
  48. 173
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  49. 4
      src/Avalonia.Base/Animation/Animatable.cs
  50. 94
      src/Avalonia.Base/Animation/Animation.AnimatorRegistry.cs
  51. 78
      src/Avalonia.Base/Animation/Animation.cs
  52. 9
      src/Avalonia.Base/Animation/AnimatorDrivenTransition.cs
  53. 4
      src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
  54. 6
      src/Avalonia.Base/Animation/AnimatorTransitionObservable.cs
  55. 2
      src/Avalonia.Base/Animation/Animators/Animator`1.cs
  56. 2
      src/Avalonia.Base/Animation/Animators/BaseBrushAnimator.cs
  57. 2
      src/Avalonia.Base/Animation/Animators/BoolAnimator.cs
  58. 2
      src/Avalonia.Base/Animation/Animators/BoxShadowAnimator.cs
  59. 2
      src/Avalonia.Base/Animation/Animators/BoxShadowsAnimator.cs
  60. 2
      src/Avalonia.Base/Animation/Animators/ByteAnimator.cs
  61. 2
      src/Avalonia.Base/Animation/Animators/ColorAnimator.cs
  62. 2
      src/Avalonia.Base/Animation/Animators/CornerRadiusAnimator.cs
  63. 2
      src/Avalonia.Base/Animation/Animators/DecimalAnimator.cs
  64. 2
      src/Avalonia.Base/Animation/Animators/DoubleAnimator.cs
  65. 2
      src/Avalonia.Base/Animation/Animators/FloatAnimator.cs
  66. 2
      src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
  67. 2
      src/Avalonia.Base/Animation/Animators/Int16Animator.cs
  68. 2
      src/Avalonia.Base/Animation/Animators/Int32Animator.cs
  69. 2
      src/Avalonia.Base/Animation/Animators/Int64Animator.cs
  70. 2
      src/Avalonia.Base/Animation/Animators/PointAnimator.cs
  71. 2
      src/Avalonia.Base/Animation/Animators/RectAnimator.cs
  72. 2
      src/Avalonia.Base/Animation/Animators/RelativePointAnimator.cs
  73. 2
      src/Avalonia.Base/Animation/Animators/SizeAnimator.cs
  74. 2
      src/Avalonia.Base/Animation/Animators/SolidColorBrushAnimator.cs
  75. 2
      src/Avalonia.Base/Animation/Animators/ThicknessAnimator.cs
  76. 2
      src/Avalonia.Base/Animation/Animators/TransformAnimator.cs
  77. 2
      src/Avalonia.Base/Animation/Animators/TransformOperationsAnimator.cs
  78. 2
      src/Avalonia.Base/Animation/Animators/UInt16Animator.cs
  79. 2
      src/Avalonia.Base/Animation/Animators/UInt32Animator.cs
  80. 2
      src/Avalonia.Base/Animation/Animators/UInt64Animator.cs
  81. 2
      src/Avalonia.Base/Animation/Animators/VectorAnimator.cs
  82. 5
      src/Avalonia.Base/Animation/Clock.cs
  83. 2
      src/Avalonia.Base/Animation/ClockBase.cs
  84. 3
      src/Avalonia.Base/Animation/Easings/IEasing.cs
  85. 5
      src/Avalonia.Base/Animation/Easings/SpringEasing.cs
  86. 4
      src/Avalonia.Base/Animation/IAnimation.cs
  87. 2
      src/Avalonia.Base/Animation/IAnimationSetter.cs
  88. 3
      src/Avalonia.Base/Animation/IAnimator.cs
  89. 3
      src/Avalonia.Base/Animation/IClock.cs
  90. 58
      src/Avalonia.Base/Animation/ICustomAnimator.cs
  91. 3
      src/Avalonia.Base/Animation/IGlobalClock.cs
  92. 4
      src/Avalonia.Base/Animation/ITransition.cs
  93. 28
      src/Avalonia.Base/Animation/InterpolatingTransitionBase.cs
  94. 2
      src/Avalonia.Base/Animation/KeyFrame.cs
  95. 2
      src/Avalonia.Base/Animation/KeyFrames.cs
  96. 2
      src/Avalonia.Base/Animation/KeySpline.cs
  97. 26
      src/Avalonia.Base/Animation/RenderLoopClock.cs
  98. 2
      src/Avalonia.Base/Animation/Spring.cs
  99. 2
      src/Avalonia.Base/Animation/SpringTypeConverter.cs
  100. 7
      src/Avalonia.Base/Animation/Transition.cs

5
.ncrunch/AppWithoutLifetime.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
</Settings>
</ProjectConfiguration>

5
.ncrunch/Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
</Settings>
</ProjectConfiguration>

5
.ncrunch/Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
</Settings>
</ProjectConfiguration>

11
Avalonia.Desktop.slnf

@ -39,14 +39,13 @@
"src\\Markup\\Avalonia.Markup.Xaml\\Avalonia.Markup.Xaml.csproj",
"src\\Markup\\Avalonia.Markup\\Avalonia.Markup.csproj",
"src\\Skia\\Avalonia.Skia\\Avalonia.Skia.csproj",
"src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
"src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
"src\\tools\\DevAnalyzers\\DevAnalyzers.csproj",
"src\\tools\\DevGenerators\\DevGenerators.csproj",
"src\\tools\\PublicAnalyzers\\Avalonia.Analyzers.csproj",
"src\\Windows\\Avalonia.Direct2D1\\Avalonia.Direct2D1.csproj",
"src\\Windows\\Avalonia.Win32.Interop\\Avalonia.Win32.Interop.csproj",
"src\\Windows\\Avalonia.Win32\\Avalonia.Win32.csproj",
"src\\tools\\Avalonia.Analyzers\\Avalonia.Analyzers.csproj",
"src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
"src\\tools\\DevAnalyzers\\DevAnalyzers.csproj",
"src\\tools\\DevGenerators\\DevGenerators.csproj",
"tests\\Avalonia.Base.UnitTests\\Avalonia.Base.UnitTests.csproj",
"tests\\Avalonia.Benchmarks\\Avalonia.Benchmarks.csproj",
"tests\\Avalonia.Controls.DataGrid.UnitTests\\Avalonia.Controls.DataGrid.UnitTests.csproj",
@ -66,4 +65,4 @@
"tests\\Avalonia.UnitTests\\Avalonia.UnitTests.csproj"
]
}
}
}

3
Avalonia.sln

@ -135,7 +135,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux", "Linux", "{86C53C40
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.LinuxFramebuffer", "src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj", "{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.Interop", "src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.Interoperability", "src\Windows\Avalonia.Win32.Interoperability\Avalonia.Win32.Interoperability.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.Skia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}"
EndProject
@ -251,6 +251,7 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppWithoutLifetime", "samples\AppWithoutLifetime\AppWithoutLifetime.csproj", "{F8928267-688E-4A51-989C-612A72446D33}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo", "samples\SafeAreaDemo\SafeAreaDemo.csproj", "{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Android", "samples\SafeAreaDemo.Android\SafeAreaDemo.Android.csproj", "{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}"

2
build/SharedVersion.props

@ -4,7 +4,7 @@
<Product>Avalonia</Product>
<Version>11.0.999</Version>
<Authors>Avalonia Team</Authors>
<Copyright>Copyright 2022 &#169; The AvaloniaUI Project</Copyright>
<Copyright>Copyright 2013-$([System.DateTime]::Now.ToString(`yyyy`)) &#169; The AvaloniaUI Project</Copyright>
<PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl>
<RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

6
dirs.proj

@ -14,11 +14,11 @@
<ProjectReference Remove="samples/*.Android/*.csproj" />
<ProjectReference Remove="samples/*.Browser/*.csproj" />
<ProjectReference Remove="samples/*.Blazor/*.csproj" />
<ProjectReference Remove="samples/ControlCatalog.Desktop/*.*proj" />
</ItemGroup>
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows')) OR '$(MSBuildRuntimeType)' != 'Full'">
<ProjectReference Remove="src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj" />
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows'))">
<ProjectReference Remove="src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj" />
<ProjectReference Remove="samples/interop/**/*.*proj" />
<ProjectReference Remove="samples/ControlCatalog.Desktop/*.*proj" />
</ItemGroup>
<!-- Build android and iOS projects only on Windows, where we have installed android workload -->

2
nukebuild/Build.cs

@ -312,7 +312,7 @@ partial class Build : NukeBuild
public static int Main() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? Execute<Build>(x => x.RunToolsTests)
? Execute<Build>(x => x.Package)
: Execute<Build>(x => x.RunTests);
}

48
nukebuild/RefAssemblyGenerator.cs

@ -71,10 +71,10 @@ public class RefAssemblyGenerator
foreach (var nested in type.NestedTypes)
ProcessType(nested, obsoleteCtor);
var hideMethods = (type.IsInterface && type.Name.EndsWith("Impl"))
var hideMembers = (type.IsInterface && type.Name.EndsWith("Impl"))
|| HasPrivateApi(type.CustomAttributes);
var injectMethod = hideMethods
var injectMethod = hideMembers
|| type.CustomAttributes.Any(a =>
a.AttributeType.FullName == "Avalonia.Metadata.NotClientImplementableAttribute");
@ -95,21 +95,57 @@ public class RefAssemblyGenerator
foreach (var m in type.Methods)
{
if (hideMethods || HasPrivateApi(m.CustomAttributes))
if (hideMembers || HasPrivateApi(m.CustomAttributes))
{
var dflags = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.FamORAssem |
MethodAttributes.FamANDAssem | MethodAttributes.Assembly;
m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly;
HideMethod(m);
}
MarkAsUnstable(m, obsoleteCtor, forceUnstable);
}
foreach (var p in type.Properties)
{
if (HasPrivateApi(p.CustomAttributes))
{
if (p.SetMethod != null)
HideMethod(p.SetMethod);
if (p.GetMethod != null)
HideMethod(p.GetMethod);
}
}
foreach (var f in type.Fields)
{
if (hideMembers || HasPrivateApi(f.CustomAttributes))
{
var dflags = FieldAttributes.Public | FieldAttributes.Family | FieldAttributes.FamORAssem |
FieldAttributes.FamANDAssem | FieldAttributes.Assembly;
f.Attributes = ((f.Attributes | dflags) ^ dflags) | FieldAttributes.Assembly;
}
}
foreach (var cl in type.NestedTypes)
{
ProcessType(cl, obsoleteCtor);
if (hideMembers)
{
var dflags = TypeAttributes.Public;
cl.Attributes = ((cl.Attributes | dflags) ^ dflags) | TypeAttributes.NotPublic;
}
}
foreach (var m in type.Properties)
MarkAsUnstable(m, obsoleteCtor, forceUnstable);
foreach (var m in type.Events)
MarkAsUnstable(m, obsoleteCtor, forceUnstable);
}
static void HideMethod(MethodDefinition m)
{
var dflags = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.FamORAssem |
MethodAttributes.FamANDAssem | MethodAttributes.Assembly;
m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly;
}
static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, ICustomAttribute unstableAttribute)
{
if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))

6
nukebuild/_build.csproj

@ -35,6 +35,12 @@
<EmbeddedResource Include="../build/avalonia.snk"></EmbeddedResource>
<Compile Remove="il-repack\ILRepack\Application.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="..\dirs.proj">
<Link>dirs.proj</Link>
</Content>
</ItemGroup>

2
packages/Avalonia/Avalonia.csproj

@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia.BuildServices" Version="0.0.16" />
<PackageReference Include="Avalonia.BuildServices" Version="0.0.19" />
<ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" />
<ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj">
<PrivateAssets>all</PrivateAssets>

1
packages/Avalonia/Avalonia.targets

@ -1,3 +1,4 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildThisFileDirectory)\AvaloniaBuildTasks.targets"/>
<Import Project="$(MSBuildThisFileDirectory)\AvaloniaPrivateApis.targets" />
</Project>

26
packages/Avalonia/AvaloniaPrivateApis.targets

@ -0,0 +1,26 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="RemoveAvaloniaRefAssemblies" AfterTargets="ResolveTargetingPackAssets" Condition="'$(AvaloniaAccessUnstablePrivateApis.ToLowerInvariant())'=='true'">
<ItemGroup>
<ReferencesToRemove Include="@(Reference)" Condition="'%(Reference.NuGetPackageId)' == 'Avalonia'" />
</ItemGroup>
<ItemGroup>
<Reference Remove="@(ReferencesToRemove)" />
</ItemGroup>
</Target>
<Target Name="PreventPackingAvaloniaUnstableApis" BeforeTargets="Pack">
<Error Condition="'$(IsPackable.ToLowerInvariant())' == 'true' and '$(AvaloniaAccessUnstablePrivateApis.ToLowerInvariant())' == 'true' and '$(Avalonia_I_Want_To_Use_Private_Apis_In_Nuget_Package_And_Promise_To_Pin_The_Exact_Avalonia_Version_In_Package_Dependency)' != 'true'"
Text="It seems that you are using private APIs in a nuget package, please follow this guide https://github.com/AvaloniaUI/Avalonia/wiki/Using-private-apis-in-nuget-packages" />
</Target>
<Target Name="AddReferencePathsToRealAvaloniaAssemblies" BeforeTargets="CoreCompile" Condition="'$(AvaloniaAccessUnstablePrivateApis.ToLowerInvariant())'=='true'">
<PropertyGroup>
<AvaloniaUnstableApiFrameworkToUse>net6.0</AvaloniaUnstableApiFrameworkToUse>
<AvaloniaUnstableApiFrameworkToUse Condition="$(TargetFramework.StartsWith('net4')) == 'true' or $(TargetFramework.StartsWith('net5')) == 'true' or $(TargetFramework.StartsWith('netsta')) == 'true' or $(TargetFramework.StartsWith('netcore')) == 'true'">netstandard2.0</AvaloniaUnstableApiFrameworkToUse>
</PropertyGroup>
<ItemGroup>
<Reference Include="$(MSBuildThisFileDirectory)/../lib/$(AvaloniaUnstableApiFrameworkToUse)/*.dll"/>
<ReferencePath Include="$(MSBuildThisFileDirectory)/../lib/$(AvaloniaUnstableApiFrameworkToUse)/*.dll"/>
<ReferencePathWithRefAssemblies Include="$(MSBuildThisFileDirectory)/../lib/$(AvaloniaUnstableApiFrameworkToUse)/*.dll"/>
</ItemGroup>
<Warning Text="AvaloniaAccessUnstablePrivateApis is Enabled: This means you are using unstable internal APIs, and your code may be depending on APIs which may change or be removed in future versions of Avalonia. Set AvaloniaAccessUnstablePrivateApis to 'False' to disable this warning." />
</Target>
</Project>

7
samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj

@ -4,10 +4,17 @@
<OutputType>Exe</OutputType>
<TargetFramework>net461</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>../ControlCatalog.NetCore/app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\ControlCatalog.NetCore\NativeControls\Win\*.cs" Link="NativeControls\*" />
</ItemGroup>
<Import Project="..\..\build\SampleApp.props" />

11
samples/ControlCatalog.Desktop/Program.cs

@ -3,6 +3,8 @@ using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Platform;
using ControlCatalog.NetCore;
using ControlCatalog.Pages;
namespace ControlCatalog
{
@ -18,6 +20,15 @@ namespace ControlCatalog
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.LogToTrace()
.AfterSetup(builder =>
{
builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()
{
StartupScreenIndex = 1,
});
EmbedSample.Implementation = new EmbedSampleWin();
})
.UsePlatformDetect();
private static void ConfigureAssetAssembly(AppBuilder builder)

1
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -16,6 +16,7 @@
<ItemGroup>
<Compile Include="..\..\src\Avalonia.X11\NativeDialogs\Gtk.cs" Link="NativeControls\Gtk\Gtk.cs" />
<Compile Include="..\..\src\Avalonia.Base\Platform\Interop\Utf8Buffer.cs" Link="NativeControls\Utf8Buffer.cs" />
</ItemGroup>
<ItemGroup>

5
samples/ControlCatalog/MainView.xaml.cs

@ -83,9 +83,10 @@ namespace ControlCatalog
if (transparencyLevels.SelectedItem is WindowTransparencyLevel selected)
{
var topLevel = (TopLevel)this.GetVisualRoot()!;
topLevel.TransparencyLevelHint = selected;
topLevel.TransparencyLevelHint = new[] { selected };
if (selected != WindowTransparencyLevel.None)
if (topLevel.ActualTransparencyLevel != WindowTransparencyLevel.None &&
topLevel.ActualTransparencyLevel == selected)
{
var transparentBrush = new ImmutableSolidColorBrush(Colors.White, 0);
var semiTransparentBrush = new ImmutableSolidColorBrush(Colors.Gray, 0.2);

4
samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs

@ -19,8 +19,8 @@ namespace ControlCatalog.Pages
customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel);
var cancellableContextBorder = this.Get<Border>("CancellableContextBorder");
cancellableContextBorder.ContextMenu!.ContextMenuClosing += ContextFlyoutPage_Closing;
cancellableContextBorder.ContextMenu!.ContextMenuOpening += ContextFlyoutPage_Opening;
cancellableContextBorder.ContextMenu!.Closing += ContextFlyoutPage_Closing;
cancellableContextBorder.ContextMenu!.Opening += ContextFlyoutPage_Opening;
}
private ContextPageViewModel? _model;

2
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -307,7 +307,7 @@ namespace ControlCatalog.Pages
Content:
";
resultText += await ReadTextFromFile(file, 10000);
resultText += await ReadTextFromFile(file, 500);
}
openedFileContent.Text = resultText;

3
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs

@ -117,9 +117,8 @@ namespace ControlCatalog.Pages
private void ScrollTo(int index)
{
System.Diagnostics.Debug.WriteLine("Scroll to " + index);
var layoutManager = ((TopLevel)VisualRoot!).LayoutManager;
var element = _repeater.GetOrCreateElement(index);
layoutManager.ExecuteLayoutPass();
((TopLevel)VisualRoot!).UpdateLayout();
element.BringIntoView();
}

29
samples/ControlCatalog/Pages/TabControlPage.xaml

@ -4,7 +4,27 @@
xmlns="https://github.com/avaloniaui"
xmlns:viewModels="using:ControlCatalog.ViewModels"
x:DataType="viewModels:TabControlPageViewModel">
<DockPanel>
<DockPanel Classes.WithContentTemplates="{Binding IsChecked, ElementName=UseContentTemplates}">
<DockPanel.Styles>
<Style Selector="DockPanel.WithContentTemplates">
<Style Selector="^ TabItem">
<Setter Property="ContentTemplate">
<DataTemplate x:CompileBindings="False">
<Border BorderBrush="Red" BorderThickness="10">
<ContentPresenter Content="{Binding}"/>
</Border>
</DataTemplate>
</Setter>
</Style>
<Style Selector="^ TabControl">
<Setter Property="ContentTemplate">
<DataTemplate>
<TextBlock Text="This template should be overriden by each TabItem's template."/>
</DataTemplate>
</Setter>
</Style>
</Style>
</DockPanel.Styles>
<TextBlock
DockPanel.Dock="Top"
Classes="h2"
@ -55,14 +75,14 @@
Margin="0 16"
DisplayMemberBinding="{Binding Header, x:DataType=viewModels:TabControlPageViewModelItem}"
TabStripPlacement="{Binding TabPlacement}">
<TabControl.ContentTemplate>
<TabControl.DataTemplates>
<DataTemplate x:DataType="viewModels:TabControlPageViewModelItem">
<StackPanel Orientation="Vertical" Spacing="8">
<TextBlock Text="{Binding Text}"/>
<Image Source="{Binding Image}" Width="300"/>
</StackPanel>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl.DataTemplates>
<TabControl.Styles>
<Style Selector="TabItem" x:DataType="viewModels:TabControlPageViewModelItem">
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
@ -78,12 +98,13 @@
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock VerticalAlignment="Center">Tab Placement:</TextBlock>
<ComboBox SelectedIndex="{Binding TabPlacement, Mode=TwoWay}">
<ComboBox SelectedIndex="{Binding TabPlacement, Mode=TwoWay}" Width="100">
<ComboBoxItem>Left</ComboBoxItem>
<ComboBoxItem>Bottom</ComboBoxItem>
<ComboBoxItem>Right</ComboBoxItem>
<ComboBoxItem>Top</ComboBoxItem>
</ComboBox>
<CheckBox Name="UseContentTemplates">Set TabItem.ContentTemplate</CheckBox>
</StackPanel>
</Grid>
</DockPanel>

2
samples/GpuInterop/MainWindow.axaml.cs

@ -11,7 +11,7 @@ namespace GpuInterop
{
InitializeComponent();
this.AttachDevTools();
Renderer.Diagnostics.DebugOverlays = RendererDebugOverlays.Fps;
RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps;
}
private void InitializeComponent()

2
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -136,7 +136,7 @@ namespace IntegrationTestApp
Name = "TransparentWindow",
SystemDecorations = SystemDecorations.None,
Background = Brushes.Transparent,
TransparencyLevelHint = WindowTransparencyLevel.Transparent,
TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent },
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Width = 200,
Height = 200,

21
samples/MobileSandbox.Desktop/MobileSandbox.Desktop.csproj

@ -4,37 +4,16 @@
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(RunNativeAotCompilation)' == 'true'">
<IlcTrimMetadata>true</IlcTrimMetadata>
<RestoreAdditionalProjectSources>https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json</RestoreAdditionalProjectSources>
<NativeAotCompilerVersion>7.0.0-*</NativeAotCompilerVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\src\Avalonia.X11\NativeDialogs\Gtk.cs" Link="NativeControls\Gtk\Gtk.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Headless\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Dialogs\Avalonia.Dialogs.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\MobileSandbox\MobileSandbox.csproj" />
<ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<!-- For native controls test -->
<PackageReference Include="MonoMac.NetStandard" Version="0.0.4" />
</ItemGroup>
<ItemGroup Condition="'$(RunNativeAotCompilation)' == 'true'">
<PackageReference Include="Microsoft.DotNet.ILCompiler" Version="$(NativeAotCompilerVersion)" />
<!-- Cross-compilation for Windows x64-arm64 and Linux x64-arm64 -->
<PackageReference Condition="'$(RuntimeIdentifier)'=='win-arm64'" Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="$(NativeAotCompilerVersion)" />
<PackageReference Condition="'$(RuntimeIdentifier)'=='linux-arm64'" Include="runtime.linux-x64.Microsoft.DotNet.ILCompiler" Version="$(NativeAotCompilerVersion)" />
</ItemGroup>
<PropertyGroup>
<!-- For Microsoft.CodeAnalysis -->
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>

15
samples/MobileSandbox/MobileSandbox.csproj

@ -14,9 +14,6 @@
<AvaloniaResource Include="Assets\*" />
<AvaloniaResource Include="Assets\Fonts\*" />
</ItemGroup>
<ItemGroup>
<None Remove="Pages\NativeEmbedPage.xaml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Assets\Fonts\SourceSansPro-Bold.ttf" />
<EmbeddedResource Include="Assets\Fonts\SourceSansPro-BoldItalic.ttf" />
@ -34,17 +31,5 @@
<ProjectReference Include="..\SampleControls\ControlSamples.csproj" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Update="Pages\NativeEmbedPage.xaml">
<Generator>MSBuild:Compile</Generator>
</AvaloniaResource>
</ItemGroup>
<ItemGroup>
<Compile Update="Pages\NativeEmbedPage.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
</ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" />
</Project>

2
samples/RenderDemo/MainWindow.xaml.cs

@ -21,7 +21,7 @@ namespace RenderDemo
void BindOverlay(Expression<Func<MainWindowViewModel, bool>> expr, RendererDebugOverlays overlay)
=> vm.WhenAnyValue(expr).Subscribe(x =>
{
var diagnostics = Renderer.Diagnostics;
var diagnostics = RendererDiagnostics;
diagnostics.DebugOverlays = x ?
diagnostics.DebugOverlays | overlay :
diagnostics.DebugOverlays & ~overlay;

4
samples/RenderDemo/Pages/AnimationsPage.xaml

@ -347,12 +347,8 @@
</UserControl.Styles>
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="False">
<StackPanel.Clock>
<Clock />
</StackPanel.Clock>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Spacing="20">
<TextBlock VerticalAlignment="Center">Hover to activate Keyframe Animations.</TextBlock>
<Button Content="{Binding PlayStateText}" Command="{Binding TogglePlayState}" Click="ToggleClock" />
</StackPanel>
<WrapPanel ClipToBounds="False">
<Border Classes="Test Rect1" Background="DarkRed"/>

15
samples/RenderDemo/Pages/AnimationsPage.xaml.cs

@ -24,20 +24,5 @@ namespace RenderDemo.Pages
{
AvaloniaXamlLoader.Load(this);
}
private void ToggleClock(object sender, RoutedEventArgs args)
{
var button = sender as Button;
var clock = button.Clock;
if (clock.PlayState == PlayState.Run)
{
clock.PlayState = PlayState.Pause;
}
else if (clock.PlayState == PlayState.Pause)
{
clock.PlayState = PlayState.Run;
}
}
}
}

12
samples/RenderDemo/Pages/CustomAnimatorPage.xaml

@ -11,10 +11,18 @@
<Style.Animations>
<Animation Duration="0:0:1" IterationCount="Infinite">
<KeyFrame Cue="0%">
<Setter Property="Text" Value="" Animation.Animator="{x:Type pages:CustomStringAnimator}"/>
<Setter Property="Text" Value="">
<Animation.Animator>
<pages:CustomStringAnimator/>
</Animation.Animator>
</Setter>
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Text" Value="0123456789" Animation.Animator="{x:Type pages:CustomStringAnimator}"/>
<Setter Property="Text" Value="0123456789" >
<Animation.Animator>
<pages:CustomStringAnimator/>
</Animation.Animator>
</Setter>
</KeyFrame>
</Animation>
</Style.Animations>

6
samples/RenderDemo/Pages/CustomStringAnimator.cs

@ -1,8 +1,10 @@
using Avalonia.Animation.Animators;
using System;
using Avalonia.Animation;
using Avalonia.Animation.Animators;
namespace RenderDemo.Pages
{
public class CustomStringAnimator : Animator<string>
public class CustomStringAnimator : InterpolatingAnimator<string>
{
public override string Interpolate(double progress, string oldValue, string newValue)
{

3
samples/RenderDemo/Pages/Transform3DPage.axaml

@ -134,9 +134,6 @@
</UserControl.Styles>
<Grid ColumnDefinitions="Auto,*,Auto,*" RowDefinitions="*, Auto, Auto, Auto, Auto, Auto, Auto, Auto">
<Grid.Clock>
<Clock />
</Grid.Clock>
<Border Name="B1" Background="DarkRed" Classes="Test">
<Border.RenderTransform>
<Rotate3DTransform CenterZ="-100"

4
samples/RenderDemo/Pages/TransitionsPage.xaml

@ -248,12 +248,8 @@
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="False">
<StackPanel.Clock>
<Clock />
</StackPanel.Clock>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Spacing="20">
<TextBlock VerticalAlignment="Center">Hover to activate Transitions.</TextBlock>
<Button Content="{Binding PlayStateText}" Command="{Binding TogglePlayState}" Click="ToggleClock" />
</StackPanel>
<WrapPanel ClipToBounds="False">
<Border Classes="Test Rect1" Background="DarkRed"/>

15
samples/RenderDemo/Pages/TransitionsPage.xaml.cs

@ -18,20 +18,5 @@ namespace RenderDemo.Pages
{
AvaloniaXamlLoader.Load(this);
}
private void ToggleClock(object sender, RoutedEventArgs args)
{
var button = sender as Button;
var clock = button.Clock;
if (clock.PlayState == PlayState.Run)
{
clock.PlayState = PlayState.Pause;
}
else if (clock.PlayState == PlayState.Pause)
{
clock.PlayState = PlayState.Run;
}
}
}
}

1
samples/Sandbox/Sandbox.csproj

@ -5,6 +5,7 @@
<TargetFramework>net6.0</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<IncludeAvaloniaGenerators>true</IncludeAvaloniaGenerators>
<!-- <AvaloniaXamlIlDebuggerLaunch>true</AvaloniaXamlIlDebuggerLaunch>-->
</PropertyGroup>
<ItemGroup>

4
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs

@ -1,4 +1,4 @@
using Avalonia.Win32.Embedding;
using Avalonia.Win32.Interoperability;
namespace WindowsInteropTest
{
@ -116,4 +116,4 @@ namespace WindowsInteropTest
private System.Windows.Forms.GroupBox groupBox2;
private WinFormsAvaloniaControlHost avaloniaHost;
}
}
}

23
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs

@ -1,35 +1,14 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Avalonia.Controls;
using Avalonia.Rendering;
using Avalonia.VisualTree;
using System.Windows.Forms;
using ControlCatalog;
namespace WindowsInteropTest
{
public partial class EmbedToWinFormsDemo : Form
{
private readonly IRenderer _renderer;
public EmbedToWinFormsDemo()
{
InitializeComponent();
avaloniaHost.Content = new MainView();
_renderer = ((TopLevel)avaloniaHost.Content.GetVisualRoot()).Renderer;
_renderer.Start();
}
protected override void OnClosed(EventArgs e)
{
_renderer.Stop();
base.OnClosed(e);
}
}
}

33
samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml

@ -1,33 +0,0 @@
<Window x:Class="WindowsInteropTest.EmbedToWpfDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:av="clr-namespace:Avalonia.Controls;assembly=Avalonia.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WindowsInteropTest"
xmlns:embedding="clr-namespace:Avalonia.Win32.Embedding;assembly=Avalonia.Win32"
xmlns:wpf="clr-namespace:Avalonia.Win32.Interop.Wpf;assembly=Avalonia.Win32.Interop"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="400" MinWidth="500" MinHeight="400">
<DockPanel>
<GroupBox DockPanel.Dock="Left" Header="WPF">
<StackPanel>
<Slider/>
<Calendar/>
</StackPanel>
</GroupBox>
<GroupBox Header="Avalonia button" DockPanel.Dock="Bottom">
<wpf:WpfAvaloniaHost >
<av:Button Content="Avalonia button"/>
</wpf:WpfAvaloniaHost>
</GroupBox>
<GroupBox Header="AvBtn" DockPanel.Dock="Right">
<wpf:WpfAvaloniaHost x:Name="RightBtn">
<av:Button Content="Avalonia button 2"/>
</wpf:WpfAvaloniaHost>
</GroupBox>
<GroupBox Header="Avalonia">
<wpf:WpfAvaloniaHost x:Name="Host"/>
</GroupBox>
</DockPanel>
</Window>

52
samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs

@ -1,52 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Rendering;
using Avalonia.VisualTree;
using ControlCatalog;
using Window = System.Windows.Window;
namespace WindowsInteropTest
{
/// <summary>
/// Interaction logic for EmbedToWpfDemo.xaml
/// </summary>
public partial class EmbedToWpfDemo : Window
{
private IRenderer _renderer;
public EmbedToWpfDemo()
{
InitializeComponent();
var view = new MainView();
Host.Content = view;
var tl = (TopLevel)view.GetVisualRoot();
tl.AttachDevTools();
_renderer = tl.Renderer;
_renderer.Start();
var btn = (Avalonia.Controls.Button) RightBtn.Content;
btn.Click += delegate
{
btn.Content += "!";
};
}
protected override void OnClosed(EventArgs e)
{
_renderer.Stop();
base.OnClosed(e);
}
}
}

9
samples/interop/WindowsInteropTest/Program.cs

@ -16,14 +16,9 @@ namespace WindowsInteropTest
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
AppBuilder.Configure<App>()
.UseWin32()
.UseDirect2D1()
.With(new Win32PlatformOptions
{
UseWindowsUIComposition = false,
ShouldRenderOnUIThread = true // necessary for WPF
})
.UseSkia()
.SetupWithoutStarting();
System.Windows.Forms.Application.Run(new SelectorForm());
System.Windows.Forms.Application.Run(new EmbedToWinFormsDemo());
}
}
}

76
samples/interop/WindowsInteropTest/SelectorForm.Designer.cs

@ -1,76 +0,0 @@
namespace WindowsInteropTest
{
partial class SelectorForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnEmbedToWinForms = new System.Windows.Forms.Button();
this.btnEmbedToWpf = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnEmbedToWinForms
//
this.btnEmbedToWinForms.Location = new System.Drawing.Point(12, 12);
this.btnEmbedToWinForms.Name = "btnEmbedToWinForms";
this.btnEmbedToWinForms.Size = new System.Drawing.Size(201, 86);
this.btnEmbedToWinForms.TabIndex = 0;
this.btnEmbedToWinForms.Text = "Embed to WinForms";
this.btnEmbedToWinForms.UseVisualStyleBackColor = true;
this.btnEmbedToWinForms.Click += new System.EventHandler(this.btnEmbedToWinForms_Click);
//
// btnEmbedToWpf
//
this.btnEmbedToWpf.Location = new System.Drawing.Point(219, 12);
this.btnEmbedToWpf.Name = "btnEmbedToWpf";
this.btnEmbedToWpf.Size = new System.Drawing.Size(201, 86);
this.btnEmbedToWpf.TabIndex = 1;
this.btnEmbedToWpf.Text = "Embed to WPF";
this.btnEmbedToWpf.UseVisualStyleBackColor = true;
this.btnEmbedToWpf.Click += new System.EventHandler(this.btnEmbedToWpf_Click);
//
// SelectorForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(432, 284);
this.Controls.Add(this.btnEmbedToWpf);
this.Controls.Add(this.btnEmbedToWinForms);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.Name = "SelectorForm";
this.Text = "Interop";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button btnEmbedToWinForms;
private System.Windows.Forms.Button btnEmbedToWpf;
}
}

30
samples/interop/WindowsInteropTest/SelectorForm.cs

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsInteropTest
{
public partial class SelectorForm : Form
{
public SelectorForm()
{
InitializeComponent();
}
private void btnEmbedToWinForms_Click(object sender, EventArgs e)
{
new EmbedToWinFormsDemo().ShowDialog(this);
}
private void btnEmbedToWpf_Click(object sender, EventArgs e)
{
new EmbedToWpfDemo().ShowDialog();
}
}
}

120
samples/interop/WindowsInteropTest/SelectorForm.resx

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

6
samples/interop/WindowsInteropTest/WindowsInteropTest.csproj

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net461</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<TargetFrameworks>net461;net6.0-windows</TargetFrameworks>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj" />
<ProjectReference Include="..\..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32.Interoperability\Avalonia.Win32.Interoperability.csproj" />
<ProjectReference Include="..\..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup>
</Project>

7
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -45,7 +45,6 @@ namespace Avalonia.Android
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoaderStub>()
.Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
if (Options.UseGpu)
@ -53,11 +52,7 @@ namespace Avalonia.Android
EglPlatformGraphics.TryInitialize();
}
Compositor = new Compositor(
AvaloniaLocator.Current.GetRequiredService<IRenderLoop>(),
AvaloniaLocator.Current.GetService<IPlatformGraphics>());
Compositor = new Compositor(AvaloniaLocator.Current.GetService<IPlatformGraphics>());
}
}

4
src/Android/Avalonia.Android/AvaloniaView.cs

@ -67,7 +67,7 @@ namespace Avalonia.Android
_timerSubscription = timer.SubscribeView(this);
}
_root.Renderer.Start();
_root.StartRendering();
if (_view.TryGetFeature<IInsetsManager>(out var insetsManager) == true)
{
@ -76,7 +76,7 @@ namespace Avalonia.Android
}
else
{
_root.Renderer.Stop();
_root.StopRendering();
_timerSubscription?.Dispose();
}
}

112
src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs

@ -5,8 +5,9 @@ using Avalonia.Input;
namespace Avalonia.Android.Platform.Input
{
internal class AndroidKeyboardDevice : KeyboardDevice, IKeyboardDevice {
private static readonly Dictionary<Keycode, Key> KeyDic = new Dictionary<Keycode, Key>
internal class AndroidKeyboardDevice : KeyboardDevice, IKeyboardDevice
{
private static readonly Dictionary<Keycode, Key> KeyDic = new Dictionary<Keycode, Key>
{
// { Keycode.Cancel?, Key.Cancel },
{ Keycode.Del, Key.Back },
@ -15,7 +16,7 @@ namespace Avalonia.Android.Platform.Input
{ Keycode.Clear, Key.Clear },
{ Keycode.Enter, Key.Return },
{ Keycode.MediaPause, Key.Pause },
//{ Keycode.?, Key.CapsLock }
{ Keycode.CapsLock, Key.CapsLock },
//{ Keycode.?, Key.HangulMode }
//{ Keycode.?, Key.JunjaMode }
//{ Keycode.?, Key.FinalMode }
@ -28,8 +29,8 @@ namespace Avalonia.Android.Platform.Input
{ Keycode.Space, Key.Space },
{ Keycode.PageUp, Key.Prior },
{ Keycode.PageDown, Key.PageDown },
// { Keycode.end?, Key.End },
{ Keycode.Home, Key.Home },
{ Keycode.MoveEnd, Key.End },
{ Keycode.MoveHome, Key.Home },
{ Keycode.DpadLeft, Key.Left },
{ Keycode.DpadUp, Key.Up },
{ Keycode.DpadRight, Key.Right },
@ -37,20 +38,20 @@ namespace Avalonia.Android.Platform.Input
// { Keycode.ButtonSelect?, Key.Select },
// { Keycode.print?, Key.Print },
//{ Keycode.execute?, Key.Execute },
// { Keycode.snap, Key.Snapshot }
//{ Keycode.snap?, Key.Snapshot }
{ Keycode.Insert, Key.Insert },
{ Keycode.ForwardDel, Key.Delete },
//{ Keycode.help, Key.Help },
//{ Keycode.?, Key.D0 }
//{ Keycode.?, Key.D1 }
//{ Keycode.?, Key.D2 }
//{ Keycode.?, Key.D3 }
//{ Keycode.?, Key.D4 }
//{ Keycode.?, Key.D5 }
//{ Keycode.?, Key.D6 }
//{ Keycode.?, Key.D7 }
//{ Keycode.?, Key.D8 }
//{ Keycode.?, Key.D9 }
{ Keycode.Help, Key.Help },
{ Keycode.Num0, Key.D0 },
{ Keycode.Num1, Key.D1 },
{ Keycode.Num2, Key.D2 },
{ Keycode.Num3, Key.D3 },
{ Keycode.Num4, Key.D4 },
{ Keycode.Num5, Key.D5 },
{ Keycode.Num6, Key.D6 },
{ Keycode.Num7, Key.D7 },
{ Keycode.Num8, Key.D8 },
{ Keycode.Num9, Key.D9 },
{ Keycode.A, Key.A },
{ Keycode.B, Key.B },
{ Keycode.C, Key.C },
@ -106,22 +107,22 @@ namespace Avalonia.Android.Platform.Input
//{ Keycode.?, Key.LWin }
//{ Keycode.?, Key.RWin }
//{ Keycode.?, Key.Apps }
//{ Keycode.?, Key.Sleep }
//{ Keycode.?, Key.NumPad0 }
//{ Keycode.?, Key.NumPad1 }
//{ Keycode.?, Key.NumPad2 }
//{ Keycode.?, Key.NumPad3 }
//{ Keycode.?, Key.NumPad4 }
//{ Keycode.?, Key.NumPad5 }
//{ Keycode.?, Key.NumPad6 }
//{ Keycode.?, Key.NumPad7 }
//{ Keycode.?, Key.NumPad8 }
//{ Keycode.?, Key.NumPad9 }
{ Keycode.Sleep, Key.Sleep },
{ Keycode.Numpad0, Key.NumPad0 },
{ Keycode.Numpad1, Key.NumPad1 },
{ Keycode.Numpad2, Key.NumPad2 },
{ Keycode.Numpad3, Key.NumPad3 },
{ Keycode.Numpad4, Key.NumPad4 },
{ Keycode.Numpad5, Key.NumPad5 },
{ Keycode.Numpad6, Key.NumPad6 },
{ Keycode.Numpad7, Key.NumPad7 },
{ Keycode.Numpad8, Key.NumPad8 },
{ Keycode.Numpad9, Key.NumPad9 },
{ Keycode.NumpadMultiply, Key.Multiply },
{ Keycode.NumpadAdd, Key.Add },
{ Keycode.NumpadComma, Key.Separator },
{ Keycode.NumpadSubtract, Key.Subtract },
//{ Keycode.numpaddecimal?, Key.Decimal }
{ Keycode.NumpadDot, Key.Decimal },
{ Keycode.NumpadDivide, Key.Divide },
{ Keycode.F1, Key.F1 },
{ Keycode.F2, Key.F2 },
@ -147,14 +148,14 @@ namespace Avalonia.Android.Platform.Input
//{ Keycode.R2, Key.F22 },
//{ Keycode.F23, Key.F23 },
//{ Keycode.R4, Key.F24 },
// { Keycode.numpad, Key.NumLock }
{ Keycode.NumLock, Key.NumLock },
{ Keycode.ScrollLock, Key.Scroll },
{ Keycode.ShiftLeft, Key.LeftShift },
//{ Keycode.?, Key.RightShift }
//{ Keycode.?, Key.LeftCtrl }
//{ Keycode.?, Key.RightCtrl }
//{ Keycode.?, Key.LeftAlt }
//{ Keycode.?, Key.RightAlt }
{ Keycode.ShiftRight, Key.RightShift },
{ Keycode.CtrlLeft, Key.LeftCtrl },
{ Keycode.CtrlRight, Key.RightCtrl },
{ Keycode.AltLeft, Key.LeftAlt },
{ Keycode.AltRight, Key.RightAlt },
//{ Keycode.?, Key.BrowserBack }
//{ Keycode.?, Key.BrowserForward }
//{ Keycode.?, Key.BrowserRefresh }
@ -163,28 +164,30 @@ namespace Avalonia.Android.Platform.Input
//{ Keycode.?, Key.BrowserFavorites }
//{ Keycode.?, Key.BrowserHome }
//{ Keycode.?, Key.VolumeMute }
//{ Keycode.?, Key.VolumeDown }
//{ Keycode.?, Key.VolumeUp }
//{ Keycode.?, Key.MediaNextTrack }
//{ Keycode.?, Key.MediaPreviousTrack }
//{ Keycode.?, Key.MediaStop }
//{ Keycode.?, Key.MediaPlayPause }
{ Keycode.VolumeDown, Key.VolumeDown },
{ Keycode.VolumeUp, Key.VolumeUp },
{ Keycode.MediaNext, Key.MediaNextTrack },
{ Keycode.MediaPrevious, Key.MediaPreviousTrack },
{ Keycode.MediaStop, Key.MediaStop },
{ Keycode.MediaPlayPause, Key.MediaPlayPause },
//{ Keycode.?, Key.LaunchMail }
//{ Keycode.?, Key.SelectMedia }
//{ Keycode.?, Key.LaunchApplication1 }
//{ Keycode.?, Key.LaunchApplication2 }
//{ Keycode.?, Key.OemSemicolon }
//{ Keycode.?, Key.OemPlus }
//{ Keycode.?, Key.OemComma }
//{ Keycode.?, Key.OemMinus }
//{ Keycode.?, Key.OemPeriod }
{ Keycode.Semicolon, Key.OemSemicolon },
{ Keycode.Plus, Key.OemPlus },
{ Keycode.Comma, Key.OemComma },
{ Keycode.Minus, Key.OemMinus },
{ Keycode.Period, Key.OemPeriod },
//{ Keycode.?, Key.Oem2 }
//{ Keycode.?, Key.OemTilde }
{ Keycode.Grave, Key.OemTilde },
//{ Keycode.?, Key.AbntC1 }
//{ Keycode.?, Key.AbntC2 }
//{ Keycode.?, Key.Oem4 }
//{ Keycode.?, Key.OemPipe }
//{ Keycode.?, Key.OemCloseBrackets }
{ Keycode.Apostrophe, Key.OemQuotes },
{ Keycode.Slash, Key.OemQuestion },
{ Keycode.LeftBracket, Key.OemOpenBrackets },
{ Keycode.RightBracket, Key.OemCloseBrackets },
//{ Keycode.?, Key.Oem7 }
//{ Keycode.?, Key.Oem8 }
//{ Keycode.?, Key.Oem102 }
@ -200,17 +203,18 @@ namespace Avalonia.Android.Platform.Input
//{ Keycode.?, Key.DbeEnterWordRegisterMode }
//{ Keycode.?, Key.DbeEnterImeConfigureMode }
//{ Keycode.?, Key.EraseEof }
//{ Keycode.?, Key.Play }
{ Keycode.MediaPlay, Key.Play },
//{ Keycode.?, Key.Zoom }
//{ Keycode.?, Key.NoName }
//{ Keycode.?, Key.DbeEnterDialogConversionMode }
//{ Keycode.?, Key.OemClear }
//{ Keycode.?, Key.DeadCharProcessed }
{ Keycode.Backslash, Key.OemBackslash }
};
internal static Key ConvertKey(Keycode key) {
Key result;
return KeyDic.TryGetValue(key, out result) ? result : Key.None;
internal static Key ConvertKey(Keycode key)
{
return KeyDic.TryGetValue(key, out var result) ? result : Key.None;
}
}
}
}

2
src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs

@ -10,7 +10,7 @@ using Avalonia.Platform;
namespace Avalonia.Android
{
internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformNativeSurfaceHandle
internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, INativePlatformHandleSurface
{
bool _invalidateQueued;
readonly object _lock = new object();

173
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;
using Android.App;
using Android.Content;
using Android.Graphics;
@ -45,6 +46,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
private readonly AndroidInsetsManager _insetsManager;
private readonly ClipboardImpl _clipboard;
private ViewImpl _view;
private WindowTransparencyLevel _transparencyLevel;
public TopLevelImpl(AvaloniaView avaloniaView, bool placeOnTop = false)
{
@ -68,6 +70,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_nativeControlHost = new AndroidNativeControlHostImpl(avaloniaView);
_storageProvider = new AndroidStorageProvider((Activity)avaloniaView.Context);
_transparencyLevel = WindowTransparencyLevel.None;
_systemNavigationManager = new AndroidSystemNavigationManagerImpl(avaloniaView.Context as IActivityNavigationService);
}
@ -103,9 +106,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IEnumerable<object> Surfaces => new object[] { _gl, _framebuffer, Handle };
public IRenderer CreateRenderer(IRenderRoot root) =>
new CompositingRenderer(root, AndroidPlatform.Compositor, () => Surfaces);
public Compositor Compositor => AndroidPlatform.Compositor;
public virtual void Hide()
{
_view.Visibility = ViewStates.Invisible;
@ -274,7 +276,18 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public Action LostFocus { get; set; }
public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; }
public WindowTransparencyLevel TransparencyLevel { get; private set; }
public WindowTransparencyLevel TransparencyLevel
{
get => _transparencyLevel;
private set
{
if (_transparencyLevel != value)
{
_transparencyLevel = value;
TransparencyLevelChanged?.Invoke(value);
}
}
}
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
{
@ -299,91 +312,64 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public double Scaling => RenderScaling;
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels)
{
if (TransparencyLevel != transparencyLevel)
if (_view.Context is not AvaloniaMainActivity activity)
return;
foreach (var level in transparencyLevels)
{
bool isBelowR = Build.VERSION.SdkInt < BuildVersionCodes.R;
bool isAboveR = Build.VERSION.SdkInt > BuildVersionCodes.R;
if (_view.Context is AvaloniaMainActivity activity)
if (!IsSupported(level))
{
continue;
}
if (level == TransparencyLevel)
{
return;
}
if (level == WindowTransparencyLevel.None)
{
if (OperatingSystem.IsAndroidVersionAtLeast(30))
{
activity.SetTranslucent(false);
}
activity.Window?.SetBackgroundDrawable(new ColorDrawable(Color.White));
}
else if (level == WindowTransparencyLevel.Transparent)
{
if (OperatingSystem.IsAndroidVersionAtLeast(30))
{
activity.SetTranslucent(true);
SetBlurBehind(activity, 0);
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}
}
else if (level == WindowTransparencyLevel.Blur)
{
switch (transparencyLevel)
if (OperatingSystem.IsAndroidVersionAtLeast(31))
{
case WindowTransparencyLevel.AcrylicBlur:
case WindowTransparencyLevel.ForceAcrylicBlur:
case WindowTransparencyLevel.Mica:
case WindowTransparencyLevel.None:
if (!isBelowR)
{
activity.SetTranslucent(false);
}
if (isAboveR)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 0;
activity.Window.Attributes = attr;
}
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));
if(transparencyLevel != WindowTransparencyLevel.None)
{
return;
}
break;
case WindowTransparencyLevel.Transparent:
if (!isBelowR)
{
activity.SetTranslucent(true);
}
if (isAboveR)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 0;
activity.Window.Attributes = attr;
}
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
break;
case WindowTransparencyLevel.Blur:
if (isAboveR)
{
activity.SetTranslucent(true);
activity.Window?.AddFlags(WindowManagerFlags.BlurBehind);
var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 120;
activity.Window.Attributes = attr;
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}
else
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));
return;
}
break;
activity.SetTranslucent(true);
SetBlurBehind(activity, 120);
activity.Window?.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}
TransparencyLevel = transparencyLevel;
}
TransparencyLevel = level;
return;
}
// If we get here, we didn't find a supported level. Use the default of None.
if (OperatingSystem.IsAndroidVersionAtLeast(30))
{
activity.SetTranslucent(false);
}
activity.Window?.SetBackgroundDrawable(new ColorDrawable(Color.White));
}
public virtual object TryGetFeature(Type featureType)
{
if (featureType == typeof(IStorageProvider))
@ -418,6 +404,31 @@ namespace Avalonia.Android.Platform.SkiaPlatform
return null;
}
private static bool IsSupported(WindowTransparencyLevel level)
{
if (level == WindowTransparencyLevel.None)
return true;
if (level == WindowTransparencyLevel.Transparent)
return OperatingSystem.IsAndroidVersionAtLeast(30);
if (level == WindowTransparencyLevel.Blur)
return OperatingSystem.IsAndroidVersionAtLeast(31);
return false;
}
private static void SetBlurBehind(AvaloniaMainActivity activity, int radius)
{
if (radius == 0)
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
else
activity.Window?.AddFlags(WindowManagerFlags.BlurBehind);
if (OperatingSystem.IsAndroidVersionAtLeast(31) && activity.Window?.Attributes is { } attr)
{
attr.BlurBehindRadius = radius;
activity.Window.Attributes = attr;
}
}
}
internal class AvaloniaInputConnection : BaseInputConnection

4
src/Avalonia.Base/Animation/Animatable.cs

@ -17,7 +17,7 @@ namespace Avalonia.Animation
/// <summary>
/// Defines the <see cref="Clock"/> property.
/// </summary>
public static readonly StyledProperty<IClock> ClockProperty =
internal static readonly StyledProperty<IClock> ClockProperty =
AvaloniaProperty.Register<Animatable, IClock>(nameof(Clock), inherits: true);
/// <summary>
@ -36,7 +36,7 @@ namespace Avalonia.Animation
/// <summary>
/// Gets or sets the clock which controls the animations on the control.
/// </summary>
public IClock Clock
internal IClock Clock
{
get => GetValue(ClockProperty);
set => SetValue(ClockProperty, value);

94
src/Avalonia.Base/Animation/Animation.AnimatorRegistry.cs

@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using Avalonia.Animation.Animators;
using Avalonia.Media;
namespace Avalonia.Animation;
partial class Animation
{
/// <summary>
/// Sets the value of the Animator attached property for a setter.
/// </summary>
/// <param name="setter">The animation setter.</param>
/// <param name="value">The property animator value.</param>
[Obsolete("CustomAnimatorBase will be removed before 11.0, use InterpolatingAnimator<T>", true)]
public static void SetAnimator(IAnimationSetter setter, CustomAnimatorBase value)
{
s_animators[setter] = (value.WrapperType, value.CreateWrapper);
}
/// <summary>
/// Sets the value of the Animator attached property for a setter.
/// </summary>
/// <param name="setter">The animation setter.</param>
/// <param name="value">The property animator value.</param>
public static void SetAnimator(IAnimationSetter setter, ICustomAnimator value)
{
s_animators[setter] = (value.WrapperType, value.CreateWrapper);
}
private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator, Func<IAnimator> Factory)>
Animators = new()
{
(prop =>(typeof(double).IsAssignableFrom(prop.PropertyType) && typeof(Transform).IsAssignableFrom(prop.OwnerType)),
typeof(TransformAnimator), () => new TransformAnimator()),
(prop => typeof(bool).IsAssignableFrom(prop.PropertyType), typeof(BoolAnimator), () => new BoolAnimator()),
(prop => typeof(byte).IsAssignableFrom(prop.PropertyType), typeof(ByteAnimator), () => new ByteAnimator()),
(prop => typeof(Int16).IsAssignableFrom(prop.PropertyType), typeof(Int16Animator), () => new Int16Animator()),
(prop => typeof(Int32).IsAssignableFrom(prop.PropertyType), typeof(Int32Animator), () => new Int32Animator()),
(prop => typeof(Int64).IsAssignableFrom(prop.PropertyType), typeof(Int64Animator), () => new Int64Animator()),
(prop => typeof(UInt16).IsAssignableFrom(prop.PropertyType), typeof(UInt16Animator), () => new UInt16Animator()),
(prop => typeof(UInt32).IsAssignableFrom(prop.PropertyType), typeof(UInt32Animator), () => new UInt32Animator()),
(prop => typeof(UInt64).IsAssignableFrom(prop.PropertyType), typeof(UInt64Animator), () => new UInt64Animator()),
(prop => typeof(float).IsAssignableFrom(prop.PropertyType), typeof(FloatAnimator), () => new FloatAnimator()),
(prop => typeof(double).IsAssignableFrom(prop.PropertyType), typeof(DoubleAnimator), () => new DoubleAnimator()),
(prop => typeof(decimal).IsAssignableFrom(prop.PropertyType), typeof(DecimalAnimator), () => new DecimalAnimator()),
};
static Animation()
{
RegisterAnimator<IEffect?, EffectAnimator>();
RegisterAnimator<BoxShadow, BoxShadowAnimator>();
RegisterAnimator<BoxShadows, BoxShadowsAnimator>();
RegisterAnimator<IBrush?, BaseBrushAnimator>();
RegisterAnimator<CornerRadius, CornerRadiusAnimator>();
RegisterAnimator<Color, ColorAnimator>();
RegisterAnimator<Vector, VectorAnimator>();
RegisterAnimator<Point, PointAnimator>();
RegisterAnimator<Rect, RectAnimator>();
RegisterAnimator<RelativePoint, RelativePointAnimator>();
RegisterAnimator<Size, SizeAnimator>();
RegisterAnimator<Thickness, ThicknessAnimator>();
}
/// <summary>
/// Registers a <see cref="Animator{T}"/> that can handle
/// a value type that matches the specified condition.
/// </summary>
static void RegisterAnimator<T, TAnimator>()
where TAnimator : Animator<T>, new()
{
Animators.Insert(0,
(prop => typeof(T).IsAssignableFrom(prop.PropertyType), typeof(TAnimator), () => new TAnimator()));
}
public static void RegisterCustomAnimator<T, TAnimator>() where TAnimator : InterpolatingAnimator<T>, new()
{
Animators.Insert(0, (prop => typeof(T).IsAssignableFrom(prop.PropertyType),
typeof(InterpolatingAnimator<T>.AnimatorWrapper), () => new TAnimator().CreateWrapper()));
}
private static (Type Type, Func<IAnimator> Factory)? GetAnimatorType(AvaloniaProperty property)
{
foreach (var (condition, type, factory) in Animators)
{
if (condition(property))
{
return (type, factory);
}
}
return null;
}
}

78
src/Avalonia.Base/Animation/Animation.cs

@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Avalonia.Reactive;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Animation.Animators;
using Avalonia.Animation.Easings;
using Avalonia.Data;
using Avalonia.Metadata;
@ -16,7 +13,7 @@ namespace Avalonia.Animation
/// <summary>
/// Tracks the progress of an animation.
/// </summary>
public class Animation : AvaloniaObject, IAnimation
public sealed partial class Animation : AvaloniaObject, IAnimation
{
/// <summary>
/// Defines the <see cref="Duration"/> property.
@ -186,7 +183,7 @@ namespace Avalonia.Animation
/// </summary>
/// <param name="setter">The animation setter.</param>
/// <returns>The property animator type.</returns>
public static (Type Type, Func<IAnimator> Factory)? GetAnimator(IAnimationSetter setter)
internal static (Type Type, Func<IAnimator> Factory)? GetAnimator(IAnimationSetter setter)
{
if (s_animators.TryGetValue(setter, out var type))
{
@ -195,62 +192,6 @@ namespace Avalonia.Animation
return null;
}
/// <summary>
/// Sets the value of the Animator attached property for a setter.
/// </summary>
/// <param name="setter">The animation setter.</param>
/// <param name="value">The property animator value.</param>
public static void SetAnimator(IAnimationSetter setter,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicMethods)]
Type value)
{
s_animators[setter] = (value, () => (IAnimator)Activator.CreateInstance(value)!);
}
private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator, Func<IAnimator> Factory)> Animators = new()
{
( prop => typeof(bool).IsAssignableFrom(prop.PropertyType), typeof(BoolAnimator), () => new BoolAnimator() ),
( prop => typeof(byte).IsAssignableFrom(prop.PropertyType), typeof(ByteAnimator), () => new ByteAnimator() ),
( prop => typeof(Int16).IsAssignableFrom(prop.PropertyType), typeof(Int16Animator), () => new Int16Animator() ),
( prop => typeof(Int32).IsAssignableFrom(prop.PropertyType), typeof(Int32Animator), () => new Int32Animator() ),
( prop => typeof(Int64).IsAssignableFrom(prop.PropertyType), typeof(Int64Animator), () => new Int64Animator() ),
( prop => typeof(UInt16).IsAssignableFrom(prop.PropertyType), typeof(UInt16Animator), () => new UInt16Animator() ),
( prop => typeof(UInt32).IsAssignableFrom(prop.PropertyType), typeof(UInt32Animator), () => new UInt32Animator() ),
( prop => typeof(UInt64).IsAssignableFrom(prop.PropertyType), typeof(UInt64Animator), () => new UInt64Animator() ),
( prop => typeof(float).IsAssignableFrom(prop.PropertyType), typeof(FloatAnimator), () => new FloatAnimator() ),
( prop => typeof(double).IsAssignableFrom(prop.PropertyType), typeof(DoubleAnimator), () => new DoubleAnimator() ),
( prop => typeof(decimal).IsAssignableFrom(prop.PropertyType), typeof(DecimalAnimator), () => new DecimalAnimator() ),
};
/// <summary>
/// Registers a <see cref="Animator{T}"/> that can handle
/// a value type that matches the specified condition.
/// </summary>
/// <param name="condition">
/// The condition to which the <see cref="Animator{T}"/>
/// is to be activated and used.
/// </param>
/// <typeparam name="TAnimator">
/// The type of the animator to instantiate.
/// </typeparam>
public static void RegisterAnimator<TAnimator>(Func<AvaloniaProperty, bool> condition)
where TAnimator : IAnimator, new()
{
Animators.Insert(0, (condition, typeof(TAnimator), () => new TAnimator()));
}
private static (Type Type, Func<IAnimator> Factory)? GetAnimatorType(AvaloniaProperty property)
{
foreach (var (condition, type, factory) in Animators)
{
if (condition(property))
{
return (type, factory);
}
}
return null;
}
private (IList<IAnimator> Animators, IList<IDisposable> subscriptions) InterpretKeyframes(Animatable control)
{
var handlerList = new Dictionary<(Type type, AvaloniaProperty Property), Func<IAnimator>>();
@ -312,8 +253,11 @@ namespace Avalonia.Animation
return (newAnimatorInstances, subscriptions);
}
IDisposable IAnimation.Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete)
=> Apply(control, clock, match, onComplete);
/// <inheritdoc/>
public IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete)
internal IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete)
{
var (animators, subscriptions) = InterpretKeyframes(control);
if (animators.Count == 1)
@ -358,14 +302,20 @@ namespace Avalonia.Animation
return new CompositeDisposable(subscriptions);
}
public Task RunAsync(Animatable control, CancellationToken cancellationToken = default) =>
RunAsync(control, null, cancellationToken);
/// <inheritdoc/>
public Task RunAsync(Animatable control, IClock? clock = null)
internal Task RunAsync(Animatable control, IClock? clock)
{
return RunAsync(control, clock, default);
}
Task IAnimation.RunAsync(Animatable control, IClock? clock, CancellationToken cancellationToken)
=> RunAsync(control, clock, cancellationToken);
/// <inheritdoc/>
public Task RunAsync(Animatable control, IClock? clock = null, CancellationToken cancellationToken = default)
internal Task RunAsync(Animatable control, IClock? clock, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{

9
src/Avalonia.Base/Animation/AnimatorDrivenTransition.cs

@ -1,5 +1,6 @@
using System;
using Avalonia.Animation.Animators;
using Avalonia.Animation.Easings;
namespace Avalonia.Animation
{
@ -8,13 +9,11 @@ namespace Avalonia.Animation
/// </summary>
/// <typeparam name="T">Type of the transitioned value.</typeparam>
/// <typeparam name="TAnimator">Type of the animator.</typeparam>
public abstract class AnimatorDrivenTransition<T, TAnimator> : Transition<T> where TAnimator : Animator<T>, new()
internal static class AnimatorDrivenTransition<T, TAnimator> where TAnimator : Animator<T>, new()
{
private static readonly TAnimator s_animator = new TAnimator();
public override IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue)
{
return new AnimatorTransitionObservable<T, TAnimator>(s_animator, progress, Easing, oldValue, newValue);
}
public static IObservable<T> Transition(IEasing easing, IObservable<double> progress, T oldValue, T newValue) =>
new AnimatorTransitionObservable<T, TAnimator>(s_animator, progress, easing, oldValue, newValue);
}
}

4
src/Avalonia.Base/Animation/AnimatorKeyFrame.cs

@ -11,7 +11,7 @@ namespace Avalonia.Animation
/// Defines a KeyFrame that is used for
/// <see cref="Animator{T}"/> objects.
/// </summary>
public class AnimatorKeyFrame : AvaloniaObject
internal class AnimatorKeyFrame : AvaloniaObject
{
public static readonly DirectProperty<AnimatorKeyFrame, object?> ValueProperty =
AvaloniaProperty.RegisterDirect<AnimatorKeyFrame, object?>(nameof(Value), k => k.Value, (k, v) => k.Value = v);
@ -67,7 +67,7 @@ namespace Avalonia.Animation
}
}
[RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
[RequiresUnreferencedCode(TrimmingMessages.TypeConversionRequiresUnreferencedCodeMessage)]
public T GetTypedValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
{
var typeConv = TypeDescriptor.GetConverter(typeof(T));

6
src/Avalonia.Base/Animation/AnimatorTransitionObservable.cs

@ -9,17 +9,15 @@ namespace Avalonia.Animation
/// </summary>
/// <typeparam name="T">Type of the transitioned value.</typeparam>
/// <typeparam name="TAnimator">Type of the animator.</typeparam>
public class AnimatorTransitionObservable<T, TAnimator> : TransitionObservableBase<T> where TAnimator : Animator<T>
internal class AnimatorTransitionObservable<T, TAnimator> : TransitionObservableBase<T> where TAnimator : Animator<T>
{
private readonly TAnimator _animator;
private readonly Easing _easing;
private readonly T _oldValue;
private readonly T _newValue;
public AnimatorTransitionObservable(TAnimator animator, IObservable<double> progress, Easing easing, T oldValue, T newValue) : base(progress, easing)
public AnimatorTransitionObservable(TAnimator animator, IObservable<double> progress, IEasing easing, T oldValue, T newValue) : base(progress, easing)
{
_animator = animator;
_easing = easing;
_oldValue = oldValue;
_newValue = newValue;
}

2
src/Avalonia.Base/Animation/Animators/Animator`1.cs

@ -11,7 +11,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Base class for <see cref="Animator{T}"/> objects
/// </summary>
public abstract class Animator<T> : AvaloniaList<AnimatorKeyFrame>, IAnimator
internal abstract class Animator<T> : AvaloniaList<AnimatorKeyFrame>, IAnimator
{
/// <summary>
/// List of type-converted keyframes.

2
src/Avalonia.Base/Animation/Animators/BaseBrushAnimator.cs

@ -15,7 +15,7 @@ namespace Avalonia.Animation.Animators
/// redirect them to the properly registered
/// animators in this class.
/// </summary>
public class BaseBrushAnimator : Animator<IBrush?>
internal class BaseBrushAnimator : Animator<IBrush?>
{
private static readonly List<(Func<Type, bool> Match, Type AnimatorType, Func<IAnimator> AnimatorFactory)> _brushAnimators = new();

2
src/Avalonia.Base/Animation/Animators/BoolAnimator.cs

@ -3,7 +3,7 @@
/// <summary>
/// Animator that handles <see cref="bool"/> properties.
/// </summary>
public class BoolAnimator : Animator<bool>
internal class BoolAnimator : Animator<bool>
{
/// <inheritdocs/>
public override bool Interpolate(double progress, bool oldValue, bool newValue)

2
src/Avalonia.Base/Animation/Animators/BoxShadowAnimator.cs

@ -2,7 +2,7 @@ using Avalonia.Media;
namespace Avalonia.Animation.Animators
{
public class BoxShadowAnimator : Animator<BoxShadow>
internal class BoxShadowAnimator : Animator<BoxShadow>
{
static ColorAnimator s_colorAnimator = new ColorAnimator();
static DoubleAnimator s_doubleAnimator = new DoubleAnimator();

2
src/Avalonia.Base/Animation/Animators/BoxShadowsAnimator.cs

@ -2,7 +2,7 @@ using Avalonia.Media;
namespace Avalonia.Animation.Animators
{
public class BoxShadowsAnimator : Animator<BoxShadows>
internal class BoxShadowsAnimator : Animator<BoxShadows>
{
private static readonly BoxShadowAnimator s_boxShadowAnimator = new BoxShadowAnimator();
public override BoxShadows Interpolate(double progress, BoxShadows oldValue, BoxShadows newValue)

2
src/Avalonia.Base/Animation/Animators/ByteAnimator.cs

@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="byte"/> properties.
/// </summary>
public class ByteAnimator : Animator<byte>
internal class ByteAnimator : Animator<byte>
{
const double maxVal = (double)byte.MaxValue;

2
src/Avalonia.Base/Animation/Animators/ColorAnimator.cs

@ -12,7 +12,7 @@ namespace Avalonia.Animation.Animators
/// Animator that interpolates <see cref="Color"/> through
/// gamma sRGB color space for better visual result.
/// </summary>
public class ColorAnimator : Animator<Color>
internal class ColorAnimator : Animator<Color>
{
/// <summary>
/// Opto-electronic conversion function for the sRGB color space.

2
src/Avalonia.Base/Animation/Animators/CornerRadiusAnimator.cs

@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="CornerRadius"/> properties.
/// </summary>
public class CornerRadiusAnimator : Animator<CornerRadius>
internal class CornerRadiusAnimator : Animator<CornerRadius>
{
public override CornerRadius Interpolate(double progress, CornerRadius oldValue, CornerRadius newValue)
{

2
src/Avalonia.Base/Animation/Animators/DecimalAnimator.cs

@ -3,7 +3,7 @@
/// <summary>
/// Animator that handles <see cref="decimal"/> properties.
/// </summary>
public class DecimalAnimator : Animator<decimal>
internal class DecimalAnimator : Animator<decimal>
{
/// <inheritdocs/>
public override decimal Interpolate(double progress, decimal oldValue, decimal newValue)

2
src/Avalonia.Base/Animation/Animators/DoubleAnimator.cs

@ -3,7 +3,7 @@
/// <summary>
/// Animator that handles <see cref="double"/> properties.
/// </summary>
public class DoubleAnimator : Animator<double>
internal class DoubleAnimator : Animator<double>
{
/// <inheritdocs/>
public override double Interpolate(double progress, double oldValue, double newValue)

2
src/Avalonia.Base/Animation/Animators/FloatAnimator.cs

@ -3,7 +3,7 @@
/// <summary>
/// Animator that handles <see cref="float"/> properties.
/// </summary>
public class FloatAnimator : Animator<float>
internal class FloatAnimator : Animator<float>
{
/// <inheritdocs/>
public override float Interpolate(double progress, float oldValue, float newValue)

2
src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs

@ -13,7 +13,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="SolidColorBrush"/> values.
/// </summary>
public class GradientBrushAnimator : Animator<IGradientBrush?>
internal class GradientBrushAnimator : Animator<IGradientBrush?>
{
private static readonly RelativePointAnimator s_relativePointAnimator = new RelativePointAnimator();
private static readonly DoubleAnimator s_doubleAnimator = new DoubleAnimator();

2
src/Avalonia.Base/Animation/Animators/Int16Animator.cs

@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="Int16"/> properties.
/// </summary>
public class Int16Animator : Animator<Int16>
internal class Int16Animator : Animator<Int16>
{
const double maxVal = (double)Int16.MaxValue;

2
src/Avalonia.Base/Animation/Animators/Int32Animator.cs

@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="Int32"/> properties.
/// </summary>
public class Int32Animator : Animator<Int32>
internal class Int32Animator : Animator<Int32>
{
const double maxVal = (double)Int32.MaxValue;

2
src/Avalonia.Base/Animation/Animators/Int64Animator.cs

@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="Int64"/> properties.
/// </summary>
public class Int64Animator : Animator<Int64>
internal class Int64Animator : Animator<Int64>
{
const double maxVal = (double)Int64.MaxValue;

2
src/Avalonia.Base/Animation/Animators/PointAnimator.cs

@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="Point"/> properties.
/// </summary>
public class PointAnimator : Animator<Point>
internal class PointAnimator : Animator<Point>
{
public override Point Interpolate(double progress, Point oldValue, Point newValue)
{

2
src/Avalonia.Base/Animation/Animators/RectAnimator.cs

@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="Rect"/> properties.
/// </summary>
public class RectAnimator : Animator<Rect>
internal class RectAnimator : Animator<Rect>
{
public override Rect Interpolate(double progress, Rect oldValue, Rect newValue)
{

2
src/Avalonia.Base/Animation/Animators/RelativePointAnimator.cs

@ -3,7 +3,7 @@
/// <summary>
/// Animator that handles <see cref="RelativePoint"/> properties.
/// </summary>
public class RelativePointAnimator : Animator<RelativePoint>
internal class RelativePointAnimator : Animator<RelativePoint>
{
private static readonly PointAnimator s_pointAnimator = new PointAnimator();

2
src/Avalonia.Base/Animation/Animators/SizeAnimator.cs

@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="Size"/> properties.
/// </summary>
public class SizeAnimator : Animator<Size>
internal class SizeAnimator : Animator<Size>
{
public override Size Interpolate(double progress, Size oldValue, Size newValue)
{

2
src/Avalonia.Base/Animation/Animators/SolidColorBrushAnimator.cs

@ -10,7 +10,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="SolidColorBrush"/> values.
/// </summary>
public class ISolidColorBrushAnimator : Animator<ISolidColorBrush?>
internal class ISolidColorBrushAnimator : Animator<ISolidColorBrush?>
{
private static readonly DoubleAnimator s_doubleAnimator = new DoubleAnimator();

2
src/Avalonia.Base/Animation/Animators/ThicknessAnimator.cs

@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="Thickness"/> properties.
/// </summary>
public class ThicknessAnimator : Animator<Thickness>
internal class ThicknessAnimator : Animator<Thickness>
{
public override Thickness Interpolate(double progress, Thickness oldValue, Thickness newValue)
{

2
src/Avalonia.Base/Animation/Animators/TransformAnimator.cs

@ -9,7 +9,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="Transform"/> properties.
/// </summary>
public class TransformAnimator : Animator<double>
internal class TransformAnimator : Animator<double>
{
DoubleAnimator? _doubleAnimator;

2
src/Avalonia.Base/Animation/Animators/TransformOperationsAnimator.cs

@ -4,7 +4,7 @@ using Avalonia.Media.Transformation;
namespace Avalonia.Animation.Animators
{
public class TransformOperationsAnimator : Animator<TransformOperations>
internal class TransformOperationsAnimator : Animator<TransformOperations>
{
public TransformOperationsAnimator()
{

2
src/Avalonia.Base/Animation/Animators/UInt16Animator.cs

@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="UInt16"/> properties.
/// </summary>
public class UInt16Animator : Animator<UInt16>
internal class UInt16Animator : Animator<UInt16>
{
const double maxVal = (double)UInt16.MaxValue;

2
src/Avalonia.Base/Animation/Animators/UInt32Animator.cs

@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="UInt32"/> properties.
/// </summary>
public class UInt32Animator : Animator<UInt32>
internal class UInt32Animator : Animator<UInt32>
{
const double maxVal = (double)UInt32.MaxValue;

2
src/Avalonia.Base/Animation/Animators/UInt64Animator.cs

@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="UInt64"/> properties.
/// </summary>
public class UInt64Animator : Animator<UInt64>
internal class UInt64Animator : Animator<UInt64>
{
const double maxVal = (double)UInt64.MaxValue;

2
src/Avalonia.Base/Animation/Animators/VectorAnimator.cs

@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
/// <summary>
/// Animator that handles <see cref="Vector"/> properties.
/// </summary>
public class VectorAnimator : Animator<Vector>
internal class VectorAnimator : Animator<Vector>
{
public override Vector Interpolate(double progress, Vector oldValue, Vector newValue)
{

5
src/Avalonia.Base/Animation/Clock.cs

@ -3,7 +3,10 @@ using Avalonia.Reactive;
namespace Avalonia.Animation
{
public class Clock : ClockBase
// Note: this class was always broken: it subscribes to the global clock immediately even it if
// doesn't actually have subscriptions
internal class Clock : ClockBase
{
public static IClock GlobalClock => AvaloniaLocator.Current.GetRequiredService<IGlobalClock>();

2
src/Avalonia.Base/Animation/ClockBase.cs

@ -3,7 +3,7 @@ using Avalonia.Reactive;
namespace Avalonia.Animation
{
public class ClockBase : IClock
internal class ClockBase : IClock
{
private readonly ClockObservable _observable;

3
src/Avalonia.Base/Animation/Easings/IEasing.cs

@ -1,8 +1,11 @@
using Avalonia.Metadata;
namespace Avalonia.Animation.Easings
{
/// <summary>
/// Defines the interface for easing classes.
/// </summary>
[NotClientImplementable]
public interface IEasing
{
/// <summary>

5
src/Avalonia.Base/Animation/Easings/SpringEasing.cs

@ -64,11 +64,6 @@ public class SpringEasing : Easing
Damping = damping;
InitialVelocity = initialVelocity;
}
public SpringEasing(Spring keySpline)
{
_internalSpring = keySpline;
}
public SpringEasing()
{

4
src/Avalonia.Base/Animation/IAnimation.cs

@ -14,11 +14,11 @@ namespace Avalonia.Animation
/// <summary>
/// Apply the animation to the specified control and run it when <paramref name="match" /> produces <c>true</c>.
/// </summary>
IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete = null);
internal IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete = null);
/// <summary>
/// Run the animation on the specified control.
/// </summary>
Task RunAsync(Animatable control, IClock clock, CancellationToken cancellationToken = default);
internal Task RunAsync(Animatable control, IClock clock, CancellationToken cancellationToken = default);
}
}

2
src/Avalonia.Base/Animation/IAnimationSetter.cs

@ -2,7 +2,7 @@ using Avalonia.Metadata;
namespace Avalonia.Animation
{
[NotClientImplementable]
[NotClientImplementable, PrivateApi]
public interface IAnimationSetter
{
AvaloniaProperty? Property { get; set; }

3
src/Avalonia.Base/Animation/IAnimator.cs

@ -7,8 +7,7 @@ namespace Avalonia.Animation
/// <summary>
/// Interface for Animator objects
/// </summary>
[NotClientImplementable]
public interface IAnimator : IList<AnimatorKeyFrame>
internal interface IAnimator : IList<AnimatorKeyFrame>
{
/// <summary>
/// The target property.

3
src/Avalonia.Base/Animation/IClock.cs

@ -3,8 +3,7 @@ using Avalonia.Metadata;
namespace Avalonia.Animation
{
[NotClientImplementable]
public interface IClock : IObservable<TimeSpan>
internal interface IClock : IObservable<TimeSpan>
{
PlayState PlayState { get; set; }
}

58
src/Avalonia.Base/Animation/ICustomAnimator.cs

@ -0,0 +1,58 @@
using System;
using Avalonia.Animation.Animators;
namespace Avalonia.Animation;
[Obsolete("This class will be removed before 11.0, use InterpolatingAnimator<T>", true)]
public abstract class CustomAnimatorBase
{
internal abstract IAnimator CreateWrapper();
internal abstract Type WrapperType { get; }
}
[Obsolete("This class will be removed before 11.0, use InterpolatingAnimator<T>", true)]
public abstract class CustomAnimatorBase<T> : CustomAnimatorBase
{
public abstract T Interpolate(double progress, T oldValue, T newValue);
internal override Type WrapperType => typeof(AnimatorWrapper);
internal override IAnimator CreateWrapper() => new AnimatorWrapper(this);
internal class AnimatorWrapper : Animator<T>
{
private readonly CustomAnimatorBase<T> _parent;
public AnimatorWrapper(CustomAnimatorBase<T> parent)
{
_parent = parent;
}
public override T Interpolate(double progress, T oldValue, T newValue) => _parent.Interpolate(progress, oldValue, newValue);
}
}
public interface ICustomAnimator
{
internal IAnimator CreateWrapper();
internal Type WrapperType { get; }
}
public abstract class InterpolatingAnimator<T> : ICustomAnimator
{
public abstract T Interpolate(double progress, T oldValue, T newValue);
Type ICustomAnimator.WrapperType => typeof(AnimatorWrapper);
IAnimator ICustomAnimator.CreateWrapper() => new AnimatorWrapper(this);
internal IAnimator CreateWrapper() => new AnimatorWrapper(this);
internal class AnimatorWrapper : Animator<T>
{
private readonly InterpolatingAnimator<T> _parent;
public AnimatorWrapper(InterpolatingAnimator<T> parent)
{
_parent = parent;
}
public override T Interpolate(double progress, T oldValue, T newValue) => _parent.Interpolate(progress, oldValue, newValue);
}
}

3
src/Avalonia.Base/Animation/IGlobalClock.cs

@ -2,8 +2,7 @@ using Avalonia.Metadata;
namespace Avalonia.Animation
{
[NotClientImplementable]
public interface IGlobalClock : IClock
internal interface IGlobalClock : IClock
{
}
}

4
src/Avalonia.Base/Animation/ITransition.cs

@ -6,13 +6,13 @@ namespace Avalonia.Animation
/// <summary>
/// Interface for Transition objects.
/// </summary>
[NotClientImplementable]
[NotClientImplementable, PrivateApi]
public interface ITransition
{
/// <summary>
/// Applies the transition to the specified <see cref="Animatable"/>.
/// </summary>
IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue);
internal IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue);
/// <summary>
/// Gets the property to be animated.

28
src/Avalonia.Base/Animation/InterpolatingTransitionBase.cs

@ -0,0 +1,28 @@
using System;
using Avalonia.Animation.Animators;
namespace Avalonia.Animation;
/// <summary>
/// The base class for user-defined transition that are doing simple value interpolation
/// </summary>
public abstract class InterpolatingTransitionBase<T> : Transition<T>
{
class Animator : Animator<T>
{
private readonly InterpolatingTransitionBase<T> _parent;
public Animator(InterpolatingTransitionBase<T> parent)
{
_parent = parent;
}
public override T Interpolate(double progress, T oldValue, T newValue) =>
_parent.Interpolate(progress, oldValue, newValue);
}
protected abstract T Interpolate(double progress, T from, T to);
internal override IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue) =>
new AnimatorTransitionObservable<T, Animator>(new Animator(this), progress, Easing, oldValue, newValue);
}

2
src/Avalonia.Base/Animation/KeyFrame.cs

@ -15,7 +15,7 @@ namespace Avalonia.Animation
/// Stores data regarding a specific key
/// point and value in an animation.
/// </summary>
public class KeyFrame : AvaloniaObject
public sealed class KeyFrame : AvaloniaObject
{
private TimeSpan _ktimeSpan;
private Cue _kCue;

2
src/Avalonia.Base/Animation/KeyFrames.cs

@ -7,7 +7,7 @@ namespace Avalonia.Animation
/// <summary>
/// A collection of <see cref="KeyFrame"/>s.
/// </summary>
public class KeyFrames : AvaloniaList<KeyFrame>
public sealed class KeyFrames : AvaloniaList<KeyFrame>
{
/// <summary>
/// Initializes a new instance of the <see cref="KeyFrames"/> class.

2
src/Avalonia.Base/Animation/KeySpline.cs

@ -17,7 +17,7 @@ namespace Avalonia.Animation
/// See https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.animation.keyspline
/// </summary>
[TypeConverter(typeof(KeySplineTypeConverter))]
public class KeySpline : AvaloniaObject
public sealed class KeySpline : AvaloniaObject
{
// Control points
private double _controlPointX1;

26
src/Avalonia.Base/Animation/RenderLoopClock.cs

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Rendering;
namespace Avalonia.Animation
{
public class RenderLoopClock : ClockBase, IRenderLoopTask, IGlobalClock
{
protected override void Stop()
{
AvaloniaLocator.Current.GetRequiredService<IRenderLoop>().Remove(this);
}
bool IRenderLoopTask.NeedsUpdate => HasSubscriptions;
void IRenderLoopTask.Render()
{
}
void IRenderLoopTask.Update(TimeSpan time)
{
Pulse(time);
}
}
}

2
src/Avalonia.Base/Animation/Spring.cs

@ -10,7 +10,7 @@ namespace Avalonia.Animation;
/// Determines how an animation is used based on spring formula.
/// </summary>
[TypeConverter(typeof(SpringTypeConverter))]
public class Spring
internal class Spring
{
private SpringSolver _springSolver;
private double _mass;

2
src/Avalonia.Base/Animation/SpringTypeConverter.cs

@ -7,7 +7,7 @@ namespace Avalonia.Animation;
/// <summary>
/// Converts string values to <see cref="Spring"/> values.
/// </summary>
public class SpringTypeConverter : TypeConverter
internal class SpringTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{

7
src/Avalonia.Base/Animation/Transition.cs

@ -53,10 +53,13 @@ namespace Avalonia.Animation
/// <summary>
/// Apply interpolation to the property.
/// </summary>
public abstract IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue);
internal abstract IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue);
/// <inheritdocs/>
public virtual IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
IDisposable ITransition.Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
=> Apply(control, clock, oldValue, newValue);
internal virtual IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
{
if (Property is null)
throw new InvalidOperationException("Transition has no property specified.");

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save