diff --git a/Avalonia.sln b/Avalonia.sln
index 5043f474c2..c8e513f94c 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -5,48 +5,26 @@ VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Visuals", "src\Avalonia.Visuals\Avalonia.Visuals.csproj", "{EB582467-6ABB-43A1-B052-E981BA910E3A}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Layout", "src\Avalonia.Layout\Avalonia.Layout.csproj", "{42472427-4774-4C81-8AFF-9F27B8E31721}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Windows", "Windows", "{B39A8919-9F95-48FE-AD7B-76E08B509888}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32", "src\Windows\Avalonia.Win32\Avalonia.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1", "src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Input", "src\Avalonia.Input\Avalonia.Input.csproj", "{62024B2D-53EB-4638-B26B-85EEAA54866E}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Interactivity", "src\Avalonia.Interactivity\Avalonia.Interactivity.csproj", "{6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls", "src\Avalonia.Controls\Avalonia.Controls.csproj", "{D2221C82-4A25-4583-9B43-D791E3F6820C}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Styling", "src\Avalonia.Styling\Avalonia.Styling.csproj", "{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Default", "src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Diagnostics", "src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj", "{7062AE20-5DCC-4442-9645-8195BDECE63E}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Animation", "src\Avalonia.Animation\Avalonia.Animation.csproj", "{D211E587-D8BC-45B9-95A4-F297C8FA5200}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Styling.UnitTests", "tests\Avalonia.Styling.UnitTests\Avalonia.Styling.UnitTests.csproj", "{47ECDF59-DEF8-4C53-87B1-2098A3429059}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.UnitTests", "tests\Avalonia.Controls.UnitTests\Avalonia.Controls.UnitTests.csproj", "{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Visuals.UnitTests", "tests\Avalonia.Visuals.UnitTests\Avalonia.Visuals.UnitTests.csproj", "{76716382-3159-460E-BDA6-C5715CF606D7}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base.UnitTests", "tests\Avalonia.Base.UnitTests\Avalonia.Base.UnitTests.csproj", "{2905FF23-53FB-45E6-AA49-6AF47A172056}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Layout.UnitTests", "tests\Avalonia.Layout.UnitTests\Avalonia.Layout.UnitTests.csproj", "{DB070A10-BF39-4752-8456-86E9D5928478}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Interactivity.UnitTests", "tests\Avalonia.Interactivity.UnitTests\Avalonia.Interactivity.UnitTests.csproj", "{08478EF5-44E8-42E9-92D6-15E00EC038D8}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1.RenderTests", "tests\Avalonia.Direct2D1.RenderTests\Avalonia.Direct2D1.RenderTests.csproj", "{DABFD304-D6A4-4752-8123-C2CCF7AC7831}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Input.UnitTests", "tests\Avalonia.Input.UnitTests\Avalonia.Input.UnitTests.csproj", "{AC18926A-E784-40FE-B09D-BB0FE2B599F0}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1.UnitTests", "tests\Avalonia.Direct2D1.UnitTests\Avalonia.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.UnitTests", "tests\Avalonia.Markup.Xaml.UnitTests\Avalonia.Markup.Xaml.UnitTests.csproj", "{99135EAB-653D-47E4-A378-C96E1278CA44}"
@@ -61,6 +39,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DE
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.cs
+ src\Shared\SourceGeneratorAttributes.cs = src\Shared\SourceGeneratorAttributes.cs
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}"
@@ -77,8 +56,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Android", "src\Android\Avalonia.Android\Avalonia.Android.csproj", "{7B92AF71-6287-4693-9DCB-BD5B6E927E23}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.AndroidTestApplication", "src\Android\Avalonia.AndroidTestApplication\Avalonia.AndroidTestApplication.csproj", "{FF69B927-C545-49AE-8E16-3D14D621AA12}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "iOS", "iOS", "{0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.iOS", "src\iOS\Avalonia.iOS\Avalonia.iOS.csproj", "{4488AD85-1495-4809-9AA4-DDFE0A48527E}"
@@ -122,7 +99,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\HarfBuzzSharp.props = build\HarfBuzzSharp.props
build\JetBrains.Annotations.props = build\JetBrains.Annotations.props
build\JetBrains.dotMemoryUnit.props = build\JetBrains.dotMemoryUnit.props
- build\Magick.NET-Q16-AnyCPU.props = build\Magick.NET-Q16-AnyCPU.props
build\Microsoft.CSharp.props = build\Microsoft.CSharp.props
build\Microsoft.Reactive.Testing.props = build\Microsoft.Reactive.Testing.props
build\Moq.props = build\Moq.props
@@ -135,11 +111,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\SharedVersion.props = build\SharedVersion.props
build\SharpDX.props = build\SharpDX.props
build\SkiaSharp.props = build\SkiaSharp.props
+ build\SourceGenerators.props = build\SourceGenerators.props
build\SourceLink.props = build\SourceLink.props
build\System.Drawing.Common.props = build\System.Drawing.Common.props
build\System.Memory.props = build\System.Memory.props
build\UnitTests.NetFX.props = build\UnitTests.NetFX.props
build\XUnit.props = build\XUnit.props
+ build\ImageSharp.props = build\ImageSharp.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{4D6FAF79-58B4-482F-9122-0668C346364C}"
@@ -185,14 +163,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Build.Tasks", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "nukebuild\_build.csproj", "{3F00BC43-5095-477F-93D8-E65B08179A00}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Animation.UnitTests", "tests\Avalonia.Animation.UnitTests\Avalonia.Animation.UnitTests.csproj", "{AF227847-E65C-4BE9-BCE9-B551357788E0}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.X11", "src\Avalonia.X11\Avalonia.X11.csproj", "{41B02319-965D-4945-8005-C1A3D1224165}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformSanityChecks", "samples\PlatformSanityChecks\PlatformSanityChecks.csproj", "{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI.UnitTests", "tests\Avalonia.ReactiveUI.UnitTests\Avalonia.ReactiveUI.UnitTests.csproj", "{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ColorPicker", "src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj", "{1ECC012A-8837-4AE2-9BDA-3E2857898727}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.DataGrid", "src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj", "{3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Dialogs", "src\Avalonia.Dialogs\Avalonia.Dialogs.csproj", "{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}"
@@ -233,10 +211,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\S
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport", "src\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj", "{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport.UnitTests", "tests\Avalonia.PlatformSupport.UnitTests\Avalonia.PlatformSupport.UnitTests.csproj", "{CE910927-CE5A-456F-BC92-E4C757354A5C}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.SourceGenerator", "src\Avalonia.SourceGenerator\Avalonia.SourceGenerator.csproj", "{CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevAnalyzers", "src\tools\DevAnalyzers\DevAnalyzers.csproj", "{2B390431-288C-435C-BB6B-A374033BD8D1}"
EndProject
Global
@@ -279,54 +259,6 @@ Global
{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhone.Build.0 = Release|Any CPU
{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhone.Build.0 = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhone.Build.0 = Debug|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|Any CPU.Build.0 = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhone.ActiveCfg = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhone.Build.0 = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhone.Build.0 = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhone.Build.0 = Debug|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|Any CPU.Build.0 = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhone.ActiveCfg = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhone.Build.0 = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -375,54 +307,6 @@ Global
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhone.Build.0 = Release|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhone.Build.0 = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhone.Build.0 = Debug|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|Any CPU.Build.0 = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhone.ActiveCfg = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhone.Build.0 = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhone.Build.0 = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhone.Build.0 = Debug|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|Any CPU.Build.0 = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhone.ActiveCfg = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhone.Build.0 = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -447,30 +331,6 @@ Global
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhone.Build.0 = Release|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhone.Build.0 = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhone.Build.0 = Debug|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|Any CPU.Build.0 = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhone.ActiveCfg = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhone.Build.0 = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -519,54 +379,6 @@ Global
{7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhone.Build.0 = Release|Any CPU
{7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhone.Build.0 = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhone.Build.0 = Debug|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|Any CPU.Build.0 = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhone.ActiveCfg = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhone.Build.0 = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhone.Build.0 = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhone.Build.0 = Debug|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|Any CPU.Build.0 = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhone.ActiveCfg = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhone.Build.0 = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -591,30 +403,6 @@ Global
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhone.Build.0 = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhone.Build.0 = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhone.Build.0 = Debug|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.Build.0 = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhone.ActiveCfg = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhone.Build.0 = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -639,54 +427,6 @@ Global
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhone.Build.0 = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhone.Build.0 = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhone.Build.0 = Debug|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Release|Any CPU.Build.0 = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhone.ActiveCfg = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhone.Build.0 = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhone.Build.0 = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhone.Build.0 = Debug|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|Any CPU.Build.0 = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhone.ActiveCfg = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhone.Build.0 = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -711,30 +451,6 @@ Global
{DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhone.Build.0 = Release|Any CPU
{DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhone.Build.0 = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhone.Build.0 = Debug|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|Any CPU.Build.0 = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhone.ActiveCfg = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhone.Build.0 = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -917,22 +633,6 @@ Global
{7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.Build.0 = Release|Any CPU
{7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|iPhone.ActiveCfg = Release|Any CPU
{7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|iPhone.ActiveCfg = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.Build.0 = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.Deploy.0 = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|iPhone.ActiveCfg = Release|Any CPU
- {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -1641,30 +1341,6 @@ Global
{3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhone.Build.0 = Release|Any CPU
{3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.AppStore|Any CPU.Build.0 = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.AppStore|iPhone.Build.0 = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Debug|iPhone.Build.0 = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|Any CPU.Build.0 = Release|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|iPhone.ActiveCfg = Release|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|iPhone.Build.0 = Release|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
@@ -2241,6 +1917,30 @@ Global
{CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|iPhone.Build.0 = Release|Any CPU
{CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|iPhone.Build.0 = Release|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
@@ -2265,6 +1965,30 @@ Global
{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhone.Build.0 = Release|Any CPU
{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhone.Build.0 = Release|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2272,14 +1996,9 @@ Global
GlobalSection(NestedProjects) = preSolution
{811A76CF-1CF6-440F-963B-BBE31BD72A82} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{3E908F67-5543-4879-A1DC-08EACE79B3CD} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
- {47ECDF59-DEF8-4C53-87B1-2098A3429059} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
- {76716382-3159-460E-BDA6-C5715CF606D7} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{2905FF23-53FB-45E6-AA49-6AF47A172056} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
- {DB070A10-BF39-4752-8456-86E9D5928478} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
- {08478EF5-44E8-42E9-92D6-15E00EC038D8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
- {AC18926A-E784-40FE-B09D-BB0FE2B599F0} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C}
@@ -2287,7 +2006,6 @@ Global
{8EF392D5-1416-45AA-9956-7CBBC3229E8A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
- {FF69B927-C545-49AE-8E16-3D14D621AA12} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
{4488AD85-1495-4809-9AA4-DDFE0A48527E} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}
{E1AA3DBF-9056-4530-9376-18119A7A3FFE} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{88060192-33D5-4932-B0F9-8BD2763E857D} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
@@ -2313,7 +2031,6 @@ Global
{E1240B49-7B4B-4371-A00E-068778C5CF0B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{D49233F8-F29C-47DD-9975-C4C9E4502720} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C}
{3C471044-3640-45E3-B1B2-16D2FF8399EE} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C}
- {AF227847-E65C-4BE9-BCE9-B551357788E0} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
diff --git a/Directory.Build.props b/Directory.Build.props
index 835decc672..42daa2df7f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,9 +1,11 @@
+
$(MSBuildThisFileDirectory)build-intermediate/nuget
$(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\netcoreapp2.0\Avalonia.Designer.HostApp.dll
false
false
+ False
diff --git a/build/ApiCompatAttributeExcludeList.txt b/build/ApiCompatAttributeExcludeList.txt
new file mode 100644
index 0000000000..1df5a30ec3
--- /dev/null
+++ b/build/ApiCompatAttributeExcludeList.txt
@@ -0,0 +1,2 @@
+T:Avalonia.Metadata.NotClientImplementableAttribute
+T:Avalonia.Metadata.UnstableAttribute
diff --git a/build/AvaloniaPublicKey.props b/build/AvaloniaPublicKey.props
new file mode 100644
index 0000000000..89215635c0
--- /dev/null
+++ b/build/AvaloniaPublicKey.props
@@ -0,0 +1,5 @@
+
+
+ 0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87
+
+
diff --git a/build/CoreLibraries.props b/build/CoreLibraries.props
index 6bf69603c0..9448a31d73 100644
--- a/build/CoreLibraries.props
+++ b/build/CoreLibraries.props
@@ -1,16 +1,8 @@
-
-
-
-
-
-
-
-
diff --git a/build/DevAnalyzers.props b/build/DevAnalyzers.props
index 28959dbd47..14e4f6a563 100644
--- a/build/DevAnalyzers.props
+++ b/build/DevAnalyzers.props
@@ -1,6 +1,6 @@
-
-
-
-
+
+
+
diff --git a/build/ImageSharp.props b/build/ImageSharp.props
new file mode 100644
index 0000000000..178c274ac9
--- /dev/null
+++ b/build/ImageSharp.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/JetBrains.dotMemoryUnit.props b/build/JetBrains.dotMemoryUnit.props
index eb4e2b6f15..5d74d474cf 100644
--- a/build/JetBrains.dotMemoryUnit.props
+++ b/build/JetBrains.dotMemoryUnit.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/Magick.NET-Q16-AnyCPU.props b/build/Magick.NET-Q16-AnyCPU.props
deleted file mode 100644
index 21d9cdcb1f..0000000000
--- a/build/Magick.NET-Q16-AnyCPU.props
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/build/NetFX.props b/build/NetFX.props
index 8ffc9ec561..14adb54035 100644
--- a/build/NetFX.props
+++ b/build/NetFX.props
@@ -1,7 +1,6 @@
-
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index a217a8272d..1ee4aa56a2 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,7 +1,7 @@
-
-
-
+
+
+
diff --git a/build/SourceGenerators.props b/build/SourceGenerators.props
new file mode 100644
index 0000000000..d000af1bf6
--- /dev/null
+++ b/build/SourceGenerators.props
@@ -0,0 +1,10 @@
+
+
+
+
+
+
diff --git a/build/SourceLink.props b/build/SourceLink.props
index 9f05848881..dd7ecc8d2a 100644
--- a/build/SourceLink.props
+++ b/build/SourceLink.props
@@ -19,7 +19,7 @@
-
+
diff --git a/native/Avalonia.Native/inc/rendertarget.h b/native/Avalonia.Native/inc/rendertarget.h
index 2b0338d099..a59915777f 100644
--- a/native/Avalonia.Native/inc/rendertarget.h
+++ b/native/Avalonia.Native/inc/rendertarget.h
@@ -1,3 +1,8 @@
+#pragma once
+
+#include "com.h"
+#include "comimpl.h"
+#include "avalonia-native.h"
@protocol IRenderTarget
-(void) setNewLayer: (CALayer*) layer;
diff --git a/native/Avalonia.Native/src/OSX/AutoFitContentView.h b/native/Avalonia.Native/src/OSX/AutoFitContentView.h
new file mode 100644
index 0000000000..7f1f764141
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/AutoFitContentView.h
@@ -0,0 +1,17 @@
+//
+// Created by Dan Walmsley on 05/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#pragma once
+
+#import
+#include "avalonia-native.h"
+
+@interface AutoFitContentView : NSView
+-(AutoFitContentView* _Nonnull) initWithContent: (NSView* _Nonnull) content;
+-(void) ShowTitleBar: (bool) show;
+-(void) SetTitleBarHeightHint: (double) height;
+
+-(void) ShowBlur: (bool) show;
+@end
\ No newline at end of file
diff --git a/native/Avalonia.Native/src/OSX/AutoFitContentView.mm b/native/Avalonia.Native/src/OSX/AutoFitContentView.mm
new file mode 100644
index 0000000000..0fa4540726
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/AutoFitContentView.mm
@@ -0,0 +1,106 @@
+//
+// Created by Dan Walmsley on 05/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#include "AvnView.h"
+#include "AutoFitContentView.h"
+#include "WindowInterfaces.h"
+#include "WindowProtocol.h"
+
+@implementation AutoFitContentView
+{
+ NSVisualEffectView* _titleBarMaterial;
+ NSBox* _titleBarUnderline;
+ NSView* _content;
+ NSVisualEffectView* _blurBehind;
+ double _titleBarHeightHint;
+ bool _settingSize;
+}
+
+-(AutoFitContentView* _Nonnull) initWithContent:(NSView *)content
+{
+ _titleBarHeightHint = -1;
+ _content = content;
+ _settingSize = false;
+
+ [self setAutoresizesSubviews:true];
+ [self setWantsLayer:true];
+
+ _titleBarMaterial = [NSVisualEffectView new];
+ [_titleBarMaterial setBlendingMode:NSVisualEffectBlendingModeWithinWindow];
+ [_titleBarMaterial setMaterial:NSVisualEffectMaterialTitlebar];
+ [_titleBarMaterial setWantsLayer:true];
+ _titleBarMaterial.hidden = true;
+
+ _titleBarUnderline = [NSBox new];
+ _titleBarUnderline.boxType = NSBoxSeparator;
+ _titleBarUnderline.fillColor = [NSColor underPageBackgroundColor];
+ _titleBarUnderline.hidden = true;
+
+ [self addSubview:_titleBarMaterial];
+ [self addSubview:_titleBarUnderline];
+
+ _blurBehind = [NSVisualEffectView new];
+ [_blurBehind setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
+ [_blurBehind setMaterial:NSVisualEffectMaterialLight];
+ [_blurBehind setWantsLayer:true];
+ _blurBehind.hidden = true;
+
+ [_blurBehind setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ [_content setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+
+ [self addSubview:_blurBehind];
+ [self addSubview:_content];
+
+ [self setWantsLayer:true];
+ return self;
+}
+
+-(void) ShowBlur:(bool)show
+{
+ _blurBehind.hidden = !show;
+}
+
+-(void) ShowTitleBar: (bool) show
+{
+ _titleBarMaterial.hidden = !show;
+ _titleBarUnderline.hidden = !show;
+}
+
+-(void) SetTitleBarHeightHint: (double) height
+{
+ _titleBarHeightHint = height;
+
+ [self setFrameSize:self.frame.size];
+}
+
+-(void)setFrameSize:(NSSize)newSize
+{
+ if(_settingSize)
+ {
+ return;
+ }
+
+ _settingSize = true;
+ [super setFrameSize:newSize];
+
+ auto window = (id ) [self window];
+
+ // TODO get actual titlebar size
+
+ double height = _titleBarHeightHint == -1 ? [window getExtendedTitleBarHeight] : _titleBarHeightHint;
+
+ NSRect tbar;
+ tbar.origin.x = 0;
+ tbar.origin.y = newSize.height - height;
+ tbar.size.width = newSize.width;
+ tbar.size.height = height;
+
+ [_titleBarMaterial setFrame:tbar];
+ tbar.size.height = height < 1 ? 0 : 1;
+ [_titleBarUnderline setFrame:tbar];
+
+ _settingSize = false;
+}
+@end
\ No newline at end of file
diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
index 7571d51c9f..6fc3977d4e 100644
--- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
+++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
@@ -7,6 +7,24 @@
objects = {
/* Begin PBXBuildFile section */
+ 18391068E48EF96E3DB5FDAB /* ResizeScope.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18391E45702740FE9DD69695 /* ResizeScope.mm */; };
+ 1839125F057B0A4EB1760058 /* WindowImpl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 183919BF108EB72A029F7671 /* WindowImpl.mm */; };
+ 183914E50CF6D2EFC1667F7C /* WindowInterfaces.h in Headers */ = {isa = PBXBuildFile; fileRef = 18391DB45C7D892E61BF388C /* WindowInterfaces.h */; };
+ 1839151F32D1BB1AB51A7BB6 /* AvnPanelWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18391884C7476DA4E53A492D /* AvnPanelWindow.mm */; };
+ 183916173528EC2737DBE5E1 /* WindowBaseImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 183915BFF0E234CD3604A7CD /* WindowBaseImpl.h */; };
+ 1839171DCC651B0638603AC4 /* INSWindowHolder.h in Headers */ = {isa = PBXBuildFile; fileRef = 18391BBB7782C296D424071F /* INSWindowHolder.h */; };
+ 1839179A55FC1421BEE83330 /* WindowBaseImpl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18391676ECF0E983F4964357 /* WindowBaseImpl.mm */; };
+ 183919D91DB9AAB5D700C2EA /* WindowImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 18391CD090AA776E7E841AC9 /* WindowImpl.h */; };
+ 18391AA7E0BBA74D184C5734 /* AutoFitContentView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1839166350F32661F3ABD70F /* AutoFitContentView.mm */; };
+ 18391AC16726CBC45856233B /* AvnWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1839155B28B20FFB672D29C6 /* AvnWindow.mm */; };
+ 18391AC65ADD7DDD33FBE737 /* PopupImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 183910513F396141938832B5 /* PopupImpl.h */; };
+ 18391C28BF1823B5464FDD36 /* ResizeScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 1839171D898F9BFC1373631A /* ResizeScope.h */; };
+ 18391CF07316F819E76B617C /* IWindowStateChanged.h in Headers */ = {isa = PBXBuildFile; fileRef = 183913C6BFD6856BD42D19FD /* IWindowStateChanged.h */; };
+ 18391D4EB311BC7EF8B8C0A6 /* AvnView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1839132D0E2454D911F1D1F9 /* AvnView.mm */; };
+ 18391D8CD1756DC858DC1A09 /* PopupImpl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18391BB698579F40F1783F31 /* PopupImpl.mm */; };
+ 18391E1381E2D5BFD60265A9 /* AutoFitContentView.h in Headers */ = {isa = PBXBuildFile; fileRef = 18391654EF0E7AB3D3AB4071 /* AutoFitContentView.h */; };
+ 18391ED5F611FF62C45F196D /* AvnView.h in Headers */ = {isa = PBXBuildFile; fileRef = 18391D1669284AD2EC9E866A /* AvnView.h */; };
+ 18391F1E2411C79405A9943A /* WindowProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 1839122E037567BDD1D09DEB /* WindowProtocol.h */; };
1A002B9E232135EE00021753 /* app.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A002B9D232135EE00021753 /* app.mm */; };
1A1852DC23E05814008F0DED /* deadlock.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A1852DB23E05814008F0DED /* deadlock.mm */; };
1A3E5EA823E9E83B00EDE661 /* rendertarget.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */; };
@@ -28,13 +46,30 @@
AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1E522B217613570091CD71 /* OpenGL.framework */; };
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; };
- AB661C202148286E00291242 /* window.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB661C1F2148286E00291242 /* window.mm */; };
AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */; };
BC11A5BE2608D58F0017BAD0 /* automation.h in Headers */ = {isa = PBXBuildFile; fileRef = BC11A5BC2608D58F0017BAD0 /* automation.h */; };
BC11A5BF2608D58F0017BAD0 /* automation.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC11A5BD2608D58F0017BAD0 /* automation.mm */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
+ 183910513F396141938832B5 /* PopupImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PopupImpl.h; sourceTree = ""; };
+ 1839122E037567BDD1D09DEB /* WindowProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowProtocol.h; sourceTree = ""; };
+ 1839132D0E2454D911F1D1F9 /* AvnView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AvnView.mm; sourceTree = ""; };
+ 183913C6BFD6856BD42D19FD /* IWindowStateChanged.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IWindowStateChanged.h; sourceTree = ""; };
+ 1839155B28B20FFB672D29C6 /* AvnWindow.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AvnWindow.mm; sourceTree = ""; };
+ 183915BFF0E234CD3604A7CD /* WindowBaseImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowBaseImpl.h; sourceTree = ""; };
+ 18391654EF0E7AB3D3AB4071 /* AutoFitContentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoFitContentView.h; sourceTree = ""; };
+ 1839166350F32661F3ABD70F /* AutoFitContentView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AutoFitContentView.mm; sourceTree = ""; };
+ 18391676ECF0E983F4964357 /* WindowBaseImpl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WindowBaseImpl.mm; sourceTree = ""; };
+ 1839171D898F9BFC1373631A /* ResizeScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResizeScope.h; sourceTree = ""; };
+ 18391884C7476DA4E53A492D /* AvnPanelWindow.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AvnPanelWindow.mm; sourceTree = ""; };
+ 183919BF108EB72A029F7671 /* WindowImpl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WindowImpl.mm; sourceTree = ""; };
+ 18391BB698579F40F1783F31 /* PopupImpl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PopupImpl.mm; sourceTree = ""; };
+ 18391BBB7782C296D424071F /* INSWindowHolder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = INSWindowHolder.h; sourceTree = ""; };
+ 18391CD090AA776E7E841AC9 /* WindowImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowImpl.h; sourceTree = ""; };
+ 18391D1669284AD2EC9E866A /* AvnView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvnView.h; sourceTree = ""; };
+ 18391DB45C7D892E61BF388C /* WindowInterfaces.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowInterfaces.h; sourceTree = ""; };
+ 18391E45702740FE9DD69695 /* ResizeScope.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ResizeScope.mm; sourceTree = ""; };
1A002B9D232135EE00021753 /* app.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = app.mm; sourceTree = ""; };
1A1852DB23E05814008F0DED /* deadlock.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = deadlock.mm; sourceTree = ""; };
1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = rendertarget.mm; sourceTree = ""; };
@@ -48,7 +83,6 @@
37A4E71A2178846A00EACBCD /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../../inc; sourceTree = ""; };
37A517B22159597E00FBA241 /* Screens.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Screens.mm; sourceTree = ""; };
37C09D8721580FE4006A6758 /* SystemDialogs.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SystemDialogs.mm; sourceTree = ""; };
- 37C09D8A21581EF2006A6758 /* window.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = window.h; sourceTree = ""; };
37DDA9AF219330F8002E132B /* AvnString.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AvnString.mm; sourceTree = ""; };
37DDA9B121933371002E132B /* AvnString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvnString.h; sourceTree = ""; };
37E2330E21583241000CB7E2 /* KeyTransform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = ""; };
@@ -62,7 +96,6 @@
AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; };
AB1E522B217613570091CD71 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
- AB661C1F2148286E00291242 /* window.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = window.mm; sourceTree = ""; };
AB661C212148288600291242 /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; };
AB7A61EF2147C815003C5833 /* libAvalonia.Native.OSX.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libAvalonia.Native.OSX.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = platformthreading.mm; sourceTree = ""; };
@@ -118,8 +151,6 @@
AB661C212148288600291242 /* common.h */,
379860FE214DA0C000CD0246 /* KeyTransform.h */,
37E2330E21583241000CB7E2 /* KeyTransform.mm */,
- AB661C1F2148286E00291242 /* window.mm */,
- 37C09D8A21581EF2006A6758 /* window.h */,
AB00E4F62147CA920032A60A /* main.mm */,
37155CE3233C00EB0034DCE9 /* menu.h */,
520624B222973F4100C4DCEF /* menu.mm */,
@@ -130,6 +161,24 @@
37C09D8721580FE4006A6758 /* SystemDialogs.mm */,
AB7A61F02147C815003C5833 /* Products */,
AB661C1C2148230E00291242 /* Frameworks */,
+ 18391676ECF0E983F4964357 /* WindowBaseImpl.mm */,
+ 183915BFF0E234CD3604A7CD /* WindowBaseImpl.h */,
+ 18391BBB7782C296D424071F /* INSWindowHolder.h */,
+ 183919BF108EB72A029F7671 /* WindowImpl.mm */,
+ 18391CD090AA776E7E841AC9 /* WindowImpl.h */,
+ 183913C6BFD6856BD42D19FD /* IWindowStateChanged.h */,
+ 18391E45702740FE9DD69695 /* ResizeScope.mm */,
+ 1839171D898F9BFC1373631A /* ResizeScope.h */,
+ 1839132D0E2454D911F1D1F9 /* AvnView.mm */,
+ 18391D1669284AD2EC9E866A /* AvnView.h */,
+ 1839166350F32661F3ABD70F /* AutoFitContentView.mm */,
+ 18391654EF0E7AB3D3AB4071 /* AutoFitContentView.h */,
+ 18391884C7476DA4E53A492D /* AvnPanelWindow.mm */,
+ 1839122E037567BDD1D09DEB /* WindowProtocol.h */,
+ 1839155B28B20FFB672D29C6 /* AvnWindow.mm */,
+ 18391DB45C7D892E61BF388C /* WindowInterfaces.h */,
+ 18391BB698579F40F1783F31 /* PopupImpl.mm */,
+ 183910513F396141938832B5 /* PopupImpl.h */,
);
sourceTree = "";
};
@@ -150,6 +199,16 @@
files = (
37155CE4233C00EB0034DCE9 /* menu.h in Headers */,
BC11A5BE2608D58F0017BAD0 /* automation.h in Headers */,
+ 183916173528EC2737DBE5E1 /* WindowBaseImpl.h in Headers */,
+ 1839171DCC651B0638603AC4 /* INSWindowHolder.h in Headers */,
+ 183919D91DB9AAB5D700C2EA /* WindowImpl.h in Headers */,
+ 18391CF07316F819E76B617C /* IWindowStateChanged.h in Headers */,
+ 18391C28BF1823B5464FDD36 /* ResizeScope.h in Headers */,
+ 18391ED5F611FF62C45F196D /* AvnView.h in Headers */,
+ 18391E1381E2D5BFD60265A9 /* AutoFitContentView.h in Headers */,
+ 18391F1E2411C79405A9943A /* WindowProtocol.h in Headers */,
+ 183914E50CF6D2EFC1667F7C /* WindowInterfaces.h in Headers */,
+ 18391AC65ADD7DDD33FBE737 /* PopupImpl.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -228,7 +287,14 @@
1A465D10246AB61600C5858B /* dnd.mm in Sources */,
AB00E4F72147CA920032A60A /* main.mm in Sources */,
37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */,
- AB661C202148286E00291242 /* window.mm in Sources */,
+ 1839179A55FC1421BEE83330 /* WindowBaseImpl.mm in Sources */,
+ 1839125F057B0A4EB1760058 /* WindowImpl.mm in Sources */,
+ 18391068E48EF96E3DB5FDAB /* ResizeScope.mm in Sources */,
+ 18391D4EB311BC7EF8B8C0A6 /* AvnView.mm in Sources */,
+ 18391AA7E0BBA74D184C5734 /* AutoFitContentView.mm in Sources */,
+ 1839151F32D1BB1AB51A7BB6 /* AvnPanelWindow.mm in Sources */,
+ 18391AC16726CBC45856233B /* AvnWindow.mm in Sources */,
+ 18391D8CD1756DC858DC1A09 /* PopupImpl.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
index 5d20a135b9..87a8312c38 100644
--- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
+++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
@@ -56,10 +56,14 @@
+
+
+
+
+#import
+#import
+#include "common.h"
+#include "WindowImpl.h"
+#include "KeyTransform.h"
+
+@class AvnAccessibilityElement;
+
+@interface AvnView : NSView
+-(AvnView* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent;
+-(NSEvent* _Nonnull) lastMouseDownEvent;
+-(AvnPoint) translateLocalPoint:(AvnPoint)pt;
+-(void) setSwRenderedFrame: (AvnFramebuffer* _Nonnull) fb dispose: (IUnknown* _Nonnull) dispose;
+-(void) onClosed;
+
+-(AvnPlatformResizeReason) getResizeReason;
+-(void) setResizeReason:(AvnPlatformResizeReason)reason;
++ (AvnPoint)toAvnPoint:(CGPoint)p;
+@end
\ No newline at end of file
diff --git a/native/Avalonia.Native/src/OSX/AvnView.mm b/native/Avalonia.Native/src/OSX/AvnView.mm
new file mode 100644
index 0000000000..02526afbcb
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/AvnView.mm
@@ -0,0 +1,712 @@
+//
+// Created by Dan Walmsley on 05/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#import
+#include "AvnView.h"
+#include "automation.h"
+#import "WindowInterfaces.h"
+
+@implementation AvnView
+{
+ ComPtr _parent;
+ NSTrackingArea* _area;
+ bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed;
+ AvnInputModifiers _modifierState;
+ NSEvent* _lastMouseDownEvent;
+ bool _lastKeyHandled;
+ AvnPixelSize _lastPixelSize;
+ NSObject* _renderTarget;
+ AvnPlatformResizeReason _resizeReason;
+ AvnAccessibilityElement* _accessibilityChild;
+}
+
+- (void)onClosed
+{
+ @synchronized (self)
+ {
+ _parent = nullptr;
+ }
+}
+
+- (NSEvent*) lastMouseDownEvent
+{
+ return _lastMouseDownEvent;
+}
+
+- (void) updateRenderTarget
+{
+ [_renderTarget resize:_lastPixelSize withScale:static_cast([[self window] backingScaleFactor])];
+ [self setNeedsDisplayInRect:[self frame]];
+}
+
+-(AvnView*) initWithParent: (WindowBaseImpl*) parent
+{
+ self = [super init];
+ _renderTarget = parent->renderTarget;
+ [self setWantsLayer:YES];
+ [self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize];
+
+ _parent = parent;
+ _area = nullptr;
+ _lastPixelSize.Height = 100;
+ _lastPixelSize.Width = 100;
+ [self registerForDraggedTypes: @[@"public.data", GetAvnCustomDataType()]];
+
+ _modifierState = AvnInputModifiersNone;
+ return self;
+}
+
+- (BOOL)isFlipped
+{
+ return YES;
+}
+
+- (BOOL)wantsUpdateLayer
+{
+ return YES;
+}
+
+- (void)setLayer:(CALayer *)layer
+{
+ [_renderTarget setNewLayer: layer];
+ [super setLayer: layer];
+}
+
+- (BOOL)isOpaque
+{
+ return YES;
+}
+
+- (BOOL)acceptsFirstResponder
+{
+ return true;
+}
+
+- (BOOL)acceptsFirstMouse:(NSEvent *)event
+{
+ return true;
+}
+
+- (BOOL)canBecomeKeyView
+{
+ return true;
+}
+
+-(void)setFrameSize:(NSSize)newSize
+{
+ [super setFrameSize:newSize];
+
+ if(_area != nullptr)
+ {
+ [self removeTrackingArea:_area];
+ _area = nullptr;
+ }
+
+ if (_parent == nullptr)
+ {
+ return;
+ }
+
+ NSRect rect = NSZeroRect;
+ rect.size = newSize;
+
+ NSTrackingAreaOptions options = NSTrackingActiveAlways | NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingEnabledDuringMouseDrag;
+ _area = [[NSTrackingArea alloc] initWithRect:rect options:options owner:self userInfo:nullptr];
+ [self addTrackingArea:_area];
+
+ _parent->UpdateCursor();
+
+ auto fsize = [self convertSizeToBacking: [self frame].size];
+
+ if(_lastPixelSize.Width != (int)fsize.width || _lastPixelSize.Height != (int)fsize.height)
+ {
+ _lastPixelSize.Width = (int)fsize.width;
+ _lastPixelSize.Height = (int)fsize.height;
+ [self updateRenderTarget];
+
+ auto reason = [self inLiveResize] ? ResizeUser : _resizeReason;
+ _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height}, reason);
+ }
+}
+
+- (void)updateLayer
+{
+ AvnInsidePotentialDeadlock deadlock;
+ if (_parent == nullptr)
+ {
+ return;
+ }
+
+ _parent->BaseEvents->RunRenderPriorityJobs();
+
+ if (_parent == nullptr)
+ {
+ return;
+ }
+
+ _parent->BaseEvents->Paint();
+}
+
+- (void)drawRect:(NSRect)dirtyRect
+{
+ return;
+}
+
+-(void) setSwRenderedFrame: (AvnFramebuffer*) fb dispose: (IUnknown*) dispose
+{
+ @autoreleasepool {
+ [_renderTarget setSwFrame:fb];
+ dispose->Release();
+ }
+}
+
+- (AvnPoint) translateLocalPoint:(AvnPoint)pt
+{
+ pt.Y = [self bounds].size.height - pt.Y;
+ return pt;
+}
+
++ (AvnPoint)toAvnPoint:(CGPoint)p
+{
+ AvnPoint result;
+
+ result.X = p.x;
+ result.Y = p.y;
+
+ return result;
+}
+
+- (void) viewDidChangeBackingProperties
+{
+ auto fsize = [self convertSizeToBacking: [self frame].size];
+ _lastPixelSize.Width = (int)fsize.width;
+ _lastPixelSize.Height = (int)fsize.height;
+ [self updateRenderTarget];
+
+ if(_parent != nullptr)
+ {
+ _parent->BaseEvents->ScalingChanged([_parent->Window backingScaleFactor]);
+ }
+
+ [super viewDidChangeBackingProperties];
+}
+
+- (bool) ignoreUserInput:(bool)trigerInputWhenDisabled
+{
+ if(_parent == nullptr)
+ {
+ return TRUE;
+ }
+
+ auto parentWindow = _parent->GetWindowProtocol();
+
+ if(parentWindow == nil || ![parentWindow shouldTryToHandleEvents])
+ {
+ if(trigerInputWhenDisabled)
+ {
+ auto window = dynamic_cast(_parent.getRaw());
+
+ if(window != nullptr)
+ {
+ window->WindowEvents->GotInputWhenDisabled();
+ }
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+- (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
+{
+ bool triggerInputWhenDisabled = type != Move;
+
+ if([self ignoreUserInput: triggerInputWhenDisabled])
+ {
+ return;
+ }
+
+ auto localPoint = [self convertPoint:[event locationInWindow] toView:self];
+ auto avnPoint = [AvnView toAvnPoint:localPoint];
+ auto point = [self translateLocalPoint:avnPoint];
+ AvnVector delta = { 0, 0};
+
+ if(type == Wheel)
+ {
+ auto speed = 5;
+
+ if([event hasPreciseScrollingDeltas])
+ {
+ speed = 50;
+ }
+
+ delta.X = [event scrollingDeltaX] / speed;
+ delta.Y = [event scrollingDeltaY] / speed;
+
+ if(delta.X == 0 && delta.Y == 0)
+ {
+ return;
+ }
+ }
+ else if (type == Magnify)
+ {
+ delta.X = delta.Y = [event magnification];
+ }
+ else if (type == Rotate)
+ {
+ delta.X = delta.Y = [event rotation];
+ }
+ else if (type == Swipe)
+ {
+ delta.X = [event deltaX];
+ delta.Y = [event deltaY];
+ }
+
+ uint32 timestamp = static_cast([event timestamp] * 1000);
+ auto modifiers = [self getModifiers:[event modifierFlags]];
+
+ if(type != Move ||
+ (
+ [self window] != nil &&
+ (
+ [[self window] firstResponder] == nil
+ || ![[[self window] firstResponder] isKindOfClass: [NSView class]]
+ )
+ )
+ )
+ [self becomeFirstResponder];
+
+ if(_parent != nullptr)
+ {
+ _parent->BaseEvents->RawMouseEvent(type, timestamp, modifiers, point, delta);
+ }
+
+ [super mouseMoved:event];
+}
+
+- (BOOL) resignFirstResponder
+{
+ _parent->BaseEvents->LostFocus();
+ return YES;
+}
+
+- (void)mouseMoved:(NSEvent *)event
+{
+ [self mouseEvent:event withType:Move];
+}
+
+- (void)mouseDown:(NSEvent *)event
+{
+ _isLeftPressed = true;
+ _lastMouseDownEvent = event;
+ [self mouseEvent:event withType:LeftButtonDown];
+}
+
+- (void)otherMouseDown:(NSEvent *)event
+{
+ _lastMouseDownEvent = event;
+
+ switch(event.buttonNumber)
+ {
+ case 2:
+ case 3:
+ _isMiddlePressed = true;
+ [self mouseEvent:event withType:MiddleButtonDown];
+ break;
+ case 4:
+ _isXButton1Pressed = true;
+ [self mouseEvent:event withType:XButton1Down];
+ break;
+ case 5:
+ _isXButton2Pressed = true;
+ [self mouseEvent:event withType:XButton2Down];
+ break;
+
+ default:
+ break;
+ }
+}
+
+- (void)rightMouseDown:(NSEvent *)event
+{
+ _isRightPressed = true;
+ _lastMouseDownEvent = event;
+ [self mouseEvent:event withType:RightButtonDown];
+}
+
+- (void)mouseUp:(NSEvent *)event
+{
+ _isLeftPressed = false;
+ [self mouseEvent:event withType:LeftButtonUp];
+}
+
+- (void)otherMouseUp:(NSEvent *)event
+{
+ switch(event.buttonNumber)
+ {
+ case 2:
+ case 3:
+ _isMiddlePressed = false;
+ [self mouseEvent:event withType:MiddleButtonUp];
+ break;
+ case 4:
+ _isXButton1Pressed = false;
+ [self mouseEvent:event withType:XButton1Up];
+ break;
+ case 5:
+ _isXButton2Pressed = false;
+ [self mouseEvent:event withType:XButton2Up];
+ break;
+
+ default:
+ break;
+ }
+}
+
+- (void)rightMouseUp:(NSEvent *)event
+{
+ _isRightPressed = false;
+ [self mouseEvent:event withType:RightButtonUp];
+}
+
+- (void)mouseDragged:(NSEvent *)event
+{
+ [self mouseEvent:event withType:Move];
+ [super mouseDragged:event];
+}
+
+- (void)otherMouseDragged:(NSEvent *)event
+{
+ [self mouseEvent:event withType:Move];
+ [super otherMouseDragged:event];
+}
+
+- (void)rightMouseDragged:(NSEvent *)event
+{
+ [self mouseEvent:event withType:Move];
+ [super rightMouseDragged:event];
+}
+
+- (void)scrollWheel:(NSEvent *)event
+{
+ [self mouseEvent:event withType:Wheel];
+ [super scrollWheel:event];
+}
+
+- (void)magnifyWithEvent:(NSEvent *)event
+{
+ [self mouseEvent:event withType:Magnify];
+ [super magnifyWithEvent:event];
+}
+
+- (void)rotateWithEvent:(NSEvent *)event
+{
+ [self mouseEvent:event withType:Rotate];
+ [super rotateWithEvent:event];
+}
+
+- (void)swipeWithEvent:(NSEvent *)event
+{
+ [self mouseEvent:event withType:Swipe];
+ [super swipeWithEvent:event];
+}
+
+- (void)mouseEntered:(NSEvent *)event
+{
+ [super mouseEntered:event];
+}
+
+- (void)mouseExited:(NSEvent *)event
+{
+ [self mouseEvent:event withType:LeaveWindow];
+ [super mouseExited:event];
+}
+
+- (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
+{
+ if([self ignoreUserInput: false])
+ {
+ return;
+ }
+
+ auto key = s_KeyMap[[event keyCode]];
+
+ uint32_t timestamp = static_cast([event timestamp] * 1000);
+ auto modifiers = [self getModifiers:[event modifierFlags]];
+
+ if(_parent != nullptr)
+ {
+ _lastKeyHandled = _parent->BaseEvents->RawKeyEvent(type, timestamp, modifiers, key);
+ }
+}
+
+- (BOOL)performKeyEquivalent:(NSEvent *)event
+{
+ bool result = _lastKeyHandled;
+
+ _lastKeyHandled = false;
+
+ return result;
+}
+
+- (void)flagsChanged:(NSEvent *)event
+{
+ auto newModifierState = [self getModifiers:[event modifierFlags]];
+
+ bool isAltCurrentlyPressed = (_modifierState & Alt) == Alt;
+ bool isControlCurrentlyPressed = (_modifierState & Control) == Control;
+ bool isShiftCurrentlyPressed = (_modifierState & Shift) == Shift;
+ bool isCommandCurrentlyPressed = (_modifierState & Windows) == Windows;
+
+ bool isAltPressed = (newModifierState & Alt) == Alt;
+ bool isControlPressed = (newModifierState & Control) == Control;
+ bool isShiftPressed = (newModifierState & Shift) == Shift;
+ bool isCommandPressed = (newModifierState & Windows) == Windows;
+
+
+ if (isAltPressed && !isAltCurrentlyPressed)
+ {
+ [self keyboardEvent:event withType:KeyDown];
+ }
+ else if (isAltCurrentlyPressed && !isAltPressed)
+ {
+ [self keyboardEvent:event withType:KeyUp];
+ }
+
+ if (isControlPressed && !isControlCurrentlyPressed)
+ {
+ [self keyboardEvent:event withType:KeyDown];
+ }
+ else if (isControlCurrentlyPressed && !isControlPressed)
+ {
+ [self keyboardEvent:event withType:KeyUp];
+ }
+
+ if (isShiftPressed && !isShiftCurrentlyPressed)
+ {
+ [self keyboardEvent:event withType:KeyDown];
+ }
+ else if(isShiftCurrentlyPressed && !isShiftPressed)
+ {
+ [self keyboardEvent:event withType:KeyUp];
+ }
+
+ if(isCommandPressed && !isCommandCurrentlyPressed)
+ {
+ [self keyboardEvent:event withType:KeyDown];
+ }
+ else if(isCommandCurrentlyPressed && ! isCommandPressed)
+ {
+ [self keyboardEvent:event withType:KeyUp];
+ }
+
+ _modifierState = newModifierState;
+
+ [[self inputContext] handleEvent:event];
+ [super flagsChanged:event];
+}
+
+- (void)keyDown:(NSEvent *)event
+{
+ [self keyboardEvent:event withType:KeyDown];
+ [[self inputContext] handleEvent:event];
+ [super keyDown:event];
+}
+
+- (void)keyUp:(NSEvent *)event
+{
+ [self keyboardEvent:event withType:KeyUp];
+ [super keyUp:event];
+}
+
+- (AvnInputModifiers)getModifiers:(NSEventModifierFlags)mod
+{
+ unsigned int rv = 0;
+
+ if (mod & NSEventModifierFlagControl)
+ rv |= Control;
+ if (mod & NSEventModifierFlagShift)
+ rv |= Shift;
+ if (mod & NSEventModifierFlagOption)
+ rv |= Alt;
+ if (mod & NSEventModifierFlagCommand)
+ rv |= Windows;
+
+ if (_isLeftPressed)
+ rv |= LeftMouseButton;
+ if (_isMiddlePressed)
+ rv |= MiddleMouseButton;
+ if (_isRightPressed)
+ rv |= RightMouseButton;
+ if (_isXButton1Pressed)
+ rv |= XButton1MouseButton;
+ if (_isXButton2Pressed)
+ rv |= XButton2MouseButton;
+
+ return (AvnInputModifiers)rv;
+}
+
+- (BOOL)hasMarkedText
+{
+ return _lastKeyHandled;
+}
+
+- (NSRange)markedRange
+{
+ return NSMakeRange(NSNotFound, 0);
+}
+
+- (NSRange)selectedRange
+{
+ return NSMakeRange(NSNotFound, 0);
+}
+
+- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
+{
+
+}
+
+- (void)unmarkText
+{
+
+}
+
+- (NSArray *)validAttributesForMarkedText
+{
+ return [NSArray new];
+}
+
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange
+{
+ return [NSAttributedString new];
+}
+
+- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
+{
+ if(!_lastKeyHandled)
+ {
+ if(_parent != nullptr)
+ {
+ _lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(0, [string UTF8String]);
+ }
+ }
+}
+
+- (NSUInteger)characterIndexForPoint:(NSPoint)point
+{
+ return 0;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange
+{
+ CGRect result = { 0 };
+
+ return result;
+}
+
+- (NSDragOperation)triggerAvnDragEvent: (AvnDragEventType) type info: (id )info
+{
+ auto localPoint = [self convertPoint:[info draggingLocation] toView:self];
+ auto avnPoint = [AvnView toAvnPoint:localPoint];
+ auto point = [self translateLocalPoint:avnPoint];
+ auto modifiers = [self getModifiers:[[NSApp currentEvent] modifierFlags]];
+ NSDragOperation nsop = [info draggingSourceOperationMask];
+
+ auto effects = ConvertDragDropEffects(nsop);
+ int reffects = (int)_parent->BaseEvents
+ ->DragEvent(type, point, modifiers, effects,
+ CreateClipboard([info draggingPasteboard], nil),
+ GetAvnDataObjectHandleFromDraggingInfo(info));
+
+ NSDragOperation ret = static_cast(0);
+
+ // Ensure that the managed part didn't add any new effects
+ reffects = (int)effects & reffects;
+
+ // OSX requires exactly one operation
+ if((reffects & (int)AvnDragDropEffects::Copy) != 0)
+ ret = NSDragOperationCopy;
+ else if((reffects & (int)AvnDragDropEffects::Move) != 0)
+ ret = NSDragOperationMove;
+ else if((reffects & (int)AvnDragDropEffects::Link) != 0)
+ ret = NSDragOperationLink;
+ if(ret == 0)
+ ret = NSDragOperationNone;
+ return ret;
+}
+
+- (NSDragOperation)draggingEntered:(id )sender
+{
+ return [self triggerAvnDragEvent: AvnDragEventType::Enter info:sender];
+}
+
+- (NSDragOperation)draggingUpdated:(id )sender
+{
+ return [self triggerAvnDragEvent: AvnDragEventType::Over info:sender];
+}
+
+- (void)draggingExited:(id )sender
+{
+ [self triggerAvnDragEvent: AvnDragEventType::Leave info:sender];
+}
+
+- (BOOL)prepareForDragOperation:(id )sender
+{
+ return [self triggerAvnDragEvent: AvnDragEventType::Over info:sender] != NSDragOperationNone;
+}
+
+- (BOOL)performDragOperation:(id )sender
+{
+ return [self triggerAvnDragEvent: AvnDragEventType::Drop info:sender] != NSDragOperationNone;
+}
+
+- (void)concludeDragOperation:(nullable id )sender
+{
+
+}
+
+- (AvnPlatformResizeReason)getResizeReason
+{
+ return _resizeReason;
+}
+
+- (void)setResizeReason:(AvnPlatformResizeReason)reason
+{
+ _resizeReason = reason;
+}
+
+- (AvnAccessibilityElement *) accessibilityChild
+{
+ if (_accessibilityChild == nil)
+ {
+ auto peer = _parent->BaseEvents->GetAutomationPeer();
+
+ if (peer == nil)
+ return nil;
+
+ _accessibilityChild = [AvnAccessibilityElement acquire:peer];
+ }
+
+ return _accessibilityChild;
+}
+
+- (NSArray *)accessibilityChildren
+{
+ auto child = [self accessibilityChild];
+ return NSAccessibilityUnignoredChildrenForOnlyChild(child);
+}
+
+- (id)accessibilityHitTest:(NSPoint)point
+{
+ return [[self accessibilityChild] accessibilityHitTest:point];
+}
+
+- (id)accessibilityFocusedUIElement
+{
+ return [[self accessibilityChild] accessibilityFocusedUIElement];
+}
+
+@end
\ No newline at end of file
diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm
new file mode 100644
index 0000000000..f51c693777
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm
@@ -0,0 +1,466 @@
+//
+// Created by Dan Walmsley on 06/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+
+#import
+#import "WindowProtocol.h"
+#import "WindowBaseImpl.h"
+
+#ifdef IS_NSPANEL
+#define BASE_CLASS NSPanel
+#define CLASS_NAME AvnPanel
+#else
+#define BASE_CLASS NSWindow
+#define CLASS_NAME AvnWindow
+#endif
+
+#import
+#include "common.h"
+#include "menu.h"
+#include "automation.h"
+#include "WindowBaseImpl.h"
+#include "WindowImpl.h"
+#include "AvnView.h"
+#include "WindowInterfaces.h"
+#include "PopupImpl.h"
+
+@implementation CLASS_NAME
+{
+ ComPtr _parent;
+ bool _closed;
+ bool _isEnabled;
+ bool _canBecomeKeyWindow;
+ bool _isExtended;
+ AvnMenu* _menu;
+}
+
+-(void) setIsExtended:(bool)value;
+{
+ _isExtended = value;
+}
+
+-(bool) isDialog
+{
+ return _parent->IsDialog();
+}
+
+-(double) getExtendedTitleBarHeight
+{
+ if(_isExtended)
+ {
+ for (id subview in self.contentView.superview.subviews)
+ {
+ if ([subview isKindOfClass:NSClassFromString(@"NSTitlebarContainerView")])
+ {
+ NSView *titlebarView = [subview subviews][0];
+
+ return (double)titlebarView.frame.size.height;
+ }
+ }
+
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+- (void)performClose:(id)sender
+{
+ if([[self delegate] respondsToSelector:@selector(windowShouldClose:)])
+ {
+ if(![[self delegate] windowShouldClose:self]) return;
+ }
+ else if([self respondsToSelector:@selector(windowShouldClose:)])
+ {
+ if(![self windowShouldClose:self]) return;
+ }
+
+ [self close];
+}
+
+- (void)pollModalSession:(nonnull NSModalSession)session
+{
+ auto response = [NSApp runModalSession:session];
+
+ if(response == NSModalResponseContinue)
+ {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self pollModalSession:session];
+ });
+ }
+ else if (!_closed)
+ {
+ [self orderOut:self];
+ [NSApp endModalSession:session];
+ }
+}
+
+-(void) showWindowMenuWithAppMenu
+{
+ if(_menu != nullptr)
+ {
+ auto appMenuItem = ::GetAppMenuItem();
+
+ if(appMenuItem != nullptr)
+ {
+ auto appMenu = [appMenuItem menu];
+
+ [appMenu removeItem:appMenuItem];
+
+ [_menu insertItem:appMenuItem atIndex:0];
+
+ [_menu setHasGlobalMenuItem:true];
+ }
+
+ [NSApp setMenu:_menu];
+ }
+ else
+ {
+ [self showAppMenuOnly];
+ }
+}
+
+-(void) showAppMenuOnly
+{
+ auto appMenuItem = ::GetAppMenuItem();
+
+ if(appMenuItem != nullptr)
+ {
+ auto appMenu = ::GetAppMenu();
+
+ auto nativeAppMenu = dynamic_cast(appMenu);
+
+ [[appMenuItem menu] removeItem:appMenuItem];
+
+ if(_menu != nullptr)
+ {
+ [_menu setHasGlobalMenuItem:false];
+ }
+
+ [nativeAppMenu->GetNative() addItem:appMenuItem];
+
+ [NSApp setMenu:nativeAppMenu->GetNative()];
+ }
+}
+
+-(void) applyMenu:(AvnMenu *)menu
+{
+ if(menu == nullptr)
+ {
+ menu = [AvnMenu new];
+ }
+
+ _menu = menu;
+}
+
+-(CLASS_NAME*) initWithParent: (WindowBaseImpl*) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask;
+{
+ // https://jameshfisher.com/2020/07/10/why-is-the-contentrect-of-my-nswindow-ignored/
+ // create nswindow with specific contentRect, otherwise we wont be able to resize the window
+ // until several ms after the window is physically on the screen.
+ self = [super initWithContentRect:contentRect styleMask: styleMask backing:NSBackingStoreBuffered defer:false];
+
+ [self setReleasedWhenClosed:false];
+ _parent = parent;
+ [self setDelegate:self];
+ _closed = false;
+ _isEnabled = true;
+
+ [self backingScaleFactor];
+ [self setOpaque:NO];
+ [self setBackgroundColor: [NSColor clearColor]];
+
+ _isExtended = false;
+
+#ifdef IS_NSPANEL
+ [self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces|NSWindowCollectionBehaviorFullScreenAuxiliary];
+#endif
+
+ return self;
+}
+
+- (BOOL)windowShouldClose:(NSWindow *)sender
+{
+ auto window = dynamic_cast(_parent.getRaw());
+
+ if(window != nullptr)
+ {
+ return !window->WindowEvents->Closing();
+ }
+
+ return true;
+}
+
+- (void)windowDidChangeBackingProperties:(NSNotification *)notification
+{
+ [self backingScaleFactor];
+}
+
+
+
+- (void)windowWillClose:(NSNotification *)notification
+{
+ _closed = true;
+ if(_parent)
+ {
+ ComPtr parent = _parent;
+ _parent = NULL;
+ [self restoreParentWindow];
+ parent->BaseEvents->Closed();
+ [parent->View onClosed];
+ }
+}
+
+-(BOOL)canBecomeKeyWindow
+{
+ if(_canBecomeKeyWindow)
+ {
+ // If the window has a child window being shown as a dialog then don't allow it to become the key window.
+ for(NSWindow* uch in [self childWindows])
+ {
+ if (![uch conformsToProtocol:@protocol(AvnWindowProtocol)])
+ {
+ continue;
+ }
+
+ id ch = (id ) uch;
+
+ if(ch.isDialog)
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+#ifndef IS_NSPANEL
+-(BOOL)canBecomeMainWindow
+{
+ return true;
+}
+#endif
+
+-(void)setCanBecomeKeyWindow:(bool)value
+{
+ _canBecomeKeyWindow = value;
+}
+
+-(bool)shouldTryToHandleEvents
+{
+ return _isEnabled;
+}
+
+-(void) setEnabled:(bool)enable
+{
+ _isEnabled = enable;
+}
+
+-(void)becomeKeyWindow
+{
+ [self showWindowMenuWithAppMenu];
+
+ if(_parent != nullptr)
+ {
+ _parent->BaseEvents->Activated();
+ }
+
+ [super becomeKeyWindow];
+}
+
+-(void) restoreParentWindow;
+{
+ auto parent = [self parentWindow];
+
+ if(parent != nil)
+ {
+ [parent removeChildWindow:self];
+ }
+}
+
+- (void)windowDidMiniaturize:(NSNotification *)notification
+{
+ auto parent = dynamic_cast(_parent.operator->());
+
+ if(parent != nullptr)
+ {
+ parent->WindowStateChanged();
+ }
+}
+
+- (void)windowDidDeminiaturize:(NSNotification *)notification
+{
+ auto parent = dynamic_cast(_parent.operator->());
+
+ if(parent != nullptr)
+ {
+ parent->WindowStateChanged();
+ }
+}
+
+- (void)windowDidResize:(NSNotification *)notification
+{
+ auto parent = dynamic_cast(_parent.operator->());
+
+ if(parent != nullptr)
+ {
+ parent->WindowStateChanged();
+ }
+}
+
+- (void)windowWillExitFullScreen:(NSNotification *)notification
+{
+ auto parent = dynamic_cast(_parent.operator->());
+
+ if(parent != nullptr)
+ {
+ parent->StartStateTransition();
+ }
+}
+
+- (void)windowDidExitFullScreen:(NSNotification *)notification
+{
+ auto parent = dynamic_cast(_parent.operator->());
+
+ if(parent != nullptr)
+ {
+ parent->EndStateTransition();
+
+ if(parent->Decorations() != SystemDecorationsFull && parent->WindowState() == Maximized)
+ {
+ NSRect screenRect = [[self screen] visibleFrame];
+ [self setFrame:screenRect display:YES];
+ }
+
+ if(parent->WindowState() == Minimized)
+ {
+ [self miniaturize:nullptr];
+ }
+
+ parent->WindowStateChanged();
+ }
+}
+
+- (void)windowWillEnterFullScreen:(NSNotification *)notification
+{
+ auto parent = dynamic_cast(_parent.operator->());
+
+ if(parent != nullptr)
+ {
+ parent->StartStateTransition();
+ }
+}
+
+- (void)windowDidEnterFullScreen:(NSNotification *)notification
+{
+ auto parent = dynamic_cast(_parent.operator->());
+
+ if(parent != nullptr)
+ {
+ parent->EndStateTransition();
+ parent->WindowStateChanged();
+ }
+}
+
+- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
+{
+ return true;
+}
+
+-(void)resignKeyWindow
+{
+ if(_parent)
+ _parent->BaseEvents->Deactivated();
+
+ [self showAppMenuOnly];
+
+ [super resignKeyWindow];
+}
+
+- (void)windowDidMove:(NSNotification *)notification
+{
+ AvnPoint position;
+
+ if(_parent != nullptr)
+ {
+ auto cparent = dynamic_cast(_parent.getRaw());
+
+ if(cparent != nullptr)
+ {
+ if(!cparent->IsShown())
+ {
+ return;
+ }
+
+ if(cparent->WindowState() == Maximized)
+ {
+ cparent->SetWindowState(Normal);
+ }
+ }
+
+ _parent->GetPosition(&position);
+ _parent->BaseEvents->PositionChanged(position);
+ }
+}
+
+- (AvnPoint) translateLocalPoint:(AvnPoint)pt
+{
+ pt.Y = [self frame].size.height - pt.Y;
+ return pt;
+}
+
+- (void)sendEvent:(NSEvent *)event
+{
+ [super sendEvent:event];
+
+ /// This is to detect non-client clicks. This can only be done on Windows... not popups, hence the dynamic_cast.
+ if(_parent != nullptr && dynamic_cast(_parent.getRaw()) != nullptr)
+ {
+ switch(event.type)
+ {
+ case NSEventTypeLeftMouseDown:
+ {
+ AvnView* view = _parent->View;
+ NSPoint windowPoint = [event locationInWindow];
+ NSPoint viewPoint = [view convertPoint:windowPoint fromView:nil];
+
+ if (!NSPointInRect(viewPoint, view.bounds))
+ {
+ auto avnPoint = [AvnView toAvnPoint:windowPoint];
+ auto point = [self translateLocalPoint:avnPoint];
+ AvnVector delta = { 0, 0 };
+
+ _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast([event timestamp] * 1000), AvnInputModifiersNone, point, delta);
+ }
+ }
+ break;
+
+ case NSEventTypeMouseEntered:
+ {
+ _parent->UpdateCursor();
+ }
+ break;
+
+ case NSEventTypeMouseExited:
+ {
+ [[NSCursor arrowCursor] set];
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+- (void)disconnectParent {
+ _parent = nullptr;
+}
+
+@end
+
diff --git a/native/Avalonia.Native/src/OSX/INSWindowHolder.h b/native/Avalonia.Native/src/OSX/INSWindowHolder.h
new file mode 100644
index 0000000000..ae64a53e7d
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/INSWindowHolder.h
@@ -0,0 +1,17 @@
+//
+// Created by Dan Walmsley on 04/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#ifndef AVALONIA_NATIVE_OSX_INSWINDOWHOLDER_H
+#define AVALONIA_NATIVE_OSX_INSWINDOWHOLDER_H
+
+@class AvnView;
+
+struct INSWindowHolder
+{
+ virtual NSWindow* _Nonnull GetNSWindow () = 0;
+ virtual NSView* _Nonnull GetNSView () = 0;
+};
+
+#endif //AVALONIA_NATIVE_OSX_INSWINDOWHOLDER_H
diff --git a/native/Avalonia.Native/src/OSX/IWindowStateChanged.h b/native/Avalonia.Native/src/OSX/IWindowStateChanged.h
new file mode 100644
index 0000000000..f0905da3ac
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/IWindowStateChanged.h
@@ -0,0 +1,18 @@
+//
+// Created by Dan Walmsley on 04/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#ifndef AVALONIA_NATIVE_OSX_IWINDOWSTATECHANGED_H
+#define AVALONIA_NATIVE_OSX_IWINDOWSTATECHANGED_H
+
+struct IWindowStateChanged
+{
+ virtual void WindowStateChanged () = 0;
+ virtual void StartStateTransition () = 0;
+ virtual void EndStateTransition () = 0;
+ virtual SystemDecorations Decorations () = 0;
+ virtual AvnWindowState WindowState () = 0;
+};
+
+#endif //AVALONIA_NATIVE_OSX_IWINDOWSTATECHANGED_H
diff --git a/native/Avalonia.Native/src/OSX/PopupImpl.h b/native/Avalonia.Native/src/OSX/PopupImpl.h
new file mode 100644
index 0000000000..451019a6a4
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/PopupImpl.h
@@ -0,0 +1,9 @@
+//
+// Created by Dan Walmsley on 06/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#ifndef AVALONIA_NATIVE_OSX_POPUPIMPL_H
+#define AVALONIA_NATIVE_OSX_POPUPIMPL_H
+
+#endif //AVALONIA_NATIVE_OSX_POPUPIMPL_H
diff --git a/native/Avalonia.Native/src/OSX/PopupImpl.mm b/native/Avalonia.Native/src/OSX/PopupImpl.mm
new file mode 100644
index 0000000000..3c5afd9424
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/PopupImpl.mm
@@ -0,0 +1,61 @@
+//
+// Created by Dan Walmsley on 06/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#include "WindowInterfaces.h"
+#include "AvnView.h"
+#include "WindowImpl.h"
+#include "automation.h"
+#include "menu.h"
+#include "common.h"
+#import "WindowBaseImpl.h"
+#import "WindowProtocol.h"
+#import
+#include "PopupImpl.h"
+
+class PopupImpl : public virtual WindowBaseImpl, public IAvnPopup
+{
+private:
+ BEGIN_INTERFACE_MAP()
+ INHERIT_INTERFACE_MAP(WindowBaseImpl)
+ INTERFACE_MAP_ENTRY(IAvnPopup, IID_IAvnPopup)
+ END_INTERFACE_MAP()
+ virtual ~PopupImpl(){}
+ ComPtr WindowEvents;
+ PopupImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl)
+ {
+ WindowEvents = events;
+ }
+protected:
+ virtual NSWindowStyleMask GetStyle() override
+ {
+ return NSWindowStyleMaskBorderless;
+ }
+
+ virtual void OnInitialiseNSWindow () override
+ {
+ [Window setLevel:NSPopUpMenuWindowLevel];
+ }
+
+public:
+ virtual bool ShouldTakeFocusOnShow() override
+ {
+ return false;
+ }
+
+ virtual HRESULT Show(bool activate, bool isDialog) override
+ {
+ return WindowBaseImpl::Show(activate, true);
+ }
+};
+
+
+extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events, IAvnGlContext* gl)
+{
+ @autoreleasepool
+ {
+ IAvnPopup* ptr = dynamic_cast(new PopupImpl(events, gl));
+ return ptr;
+ }
+}
diff --git a/native/Avalonia.Native/src/OSX/ResizeScope.h b/native/Avalonia.Native/src/OSX/ResizeScope.h
new file mode 100644
index 0000000000..9a43c158fe
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/ResizeScope.h
@@ -0,0 +1,24 @@
+//
+// Created by Dan Walmsley on 04/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#ifndef AVALONIA_NATIVE_OSX_RESIZESCOPE_H
+#define AVALONIA_NATIVE_OSX_RESIZESCOPE_H
+
+#include "avalonia-native.h"
+
+@class AvnView;
+
+class ResizeScope
+{
+public:
+ ResizeScope(AvnView* _Nonnull view, AvnPlatformResizeReason reason);
+
+ ~ResizeScope();
+private:
+ AvnView* _Nonnull _view;
+ AvnPlatformResizeReason _restore;
+};
+
+#endif //AVALONIA_NATIVE_OSX_RESIZESCOPE_H
diff --git a/native/Avalonia.Native/src/OSX/ResizeScope.mm b/native/Avalonia.Native/src/OSX/ResizeScope.mm
new file mode 100644
index 0000000000..9f1177af8b
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/ResizeScope.mm
@@ -0,0 +1,18 @@
+//
+// Created by Dan Walmsley on 04/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#import
+#include "ResizeScope.h"
+#include "AvnView.h"
+
+ResizeScope::ResizeScope(AvnView *view, AvnPlatformResizeReason reason) {
+ _view = view;
+ _restore = [view getResizeReason];
+ [view setResizeReason:reason];
+}
+
+ResizeScope::~ResizeScope() {
+ [_view setResizeReason:_restore];
+}
diff --git a/native/Avalonia.Native/src/OSX/SystemDialogs.mm b/native/Avalonia.Native/src/OSX/SystemDialogs.mm
index a47221056b..535b6c3b66 100644
--- a/native/Avalonia.Native/src/OSX/SystemDialogs.mm
+++ b/native/Avalonia.Native/src/OSX/SystemDialogs.mm
@@ -1,5 +1,5 @@
#include "common.h"
-#include "window.h"
+#include "INSWindowHolder.h"
class SystemDialogs : public ComSingleObject
{
diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h
new file mode 100644
index 0000000000..83850e780c
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h
@@ -0,0 +1,136 @@
+//
+// Created by Dan Walmsley on 04/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#ifndef AVALONIA_NATIVE_OSX_WINDOWBASEIMPL_H
+#define AVALONIA_NATIVE_OSX_WINDOWBASEIMPL_H
+
+#include "rendertarget.h"
+#include "INSWindowHolder.h"
+
+@class AutoFitContentView;
+@class AvnMenu;
+@protocol AvnWindowProtocol;
+
+class WindowBaseImpl : public virtual ComObject,
+ public virtual IAvnWindowBase,
+ public INSWindowHolder {
+
+public:
+ FORWARD_IUNKNOWN()
+
+BEGIN_INTERFACE_MAP()
+ INTERFACE_MAP_ENTRY(IAvnWindowBase, IID_IAvnWindowBase)
+ END_INTERFACE_MAP()
+
+ virtual ~WindowBaseImpl();
+
+ WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl);
+
+ virtual HRESULT ObtainNSWindowHandle(void **ret) override;
+
+ virtual HRESULT ObtainNSWindowHandleRetained(void **ret) override;
+
+ virtual HRESULT ObtainNSViewHandle(void **ret) override;
+
+ virtual HRESULT ObtainNSViewHandleRetained(void **ret) override;
+
+ virtual NSWindow *GetNSWindow() override;
+
+ virtual NSView *GetNSView() override;
+
+ virtual HRESULT Show(bool activate, bool isDialog) override;
+
+ virtual bool IsShown ();
+
+ virtual bool ShouldTakeFocusOnShow();
+
+ virtual HRESULT Hide() override;
+
+ virtual HRESULT Activate() override;
+
+ virtual HRESULT SetTopMost(bool value) override;
+
+ virtual HRESULT Close() override;
+
+ virtual HRESULT GetClientSize(AvnSize *ret) override;
+
+ virtual HRESULT GetFrameSize(AvnSize *ret) override;
+
+ virtual HRESULT GetScaling(double *ret) override;
+
+ virtual HRESULT SetMinMaxSize(AvnSize minSize, AvnSize maxSize) override;
+
+ virtual HRESULT Resize(double x, double y, AvnPlatformResizeReason reason) override;
+
+ virtual HRESULT Invalidate(__attribute__((unused)) AvnRect rect) override;
+
+ virtual HRESULT SetMainMenu(IAvnMenu *menu) override;
+
+ virtual HRESULT BeginMoveDrag() override;
+
+ virtual HRESULT BeginResizeDrag(__attribute__((unused)) AvnWindowEdge edge) override;
+
+ virtual HRESULT GetPosition(AvnPoint *ret) override;
+
+ virtual HRESULT SetPosition(AvnPoint point) override;
+
+ virtual HRESULT PointToClient(AvnPoint point, AvnPoint *ret) override;
+
+ virtual HRESULT PointToScreen(AvnPoint point, AvnPoint *ret) override;
+
+ virtual HRESULT ThreadSafeSetSwRenderedFrame(AvnFramebuffer *fb, IUnknown *dispose) override;
+
+ virtual HRESULT SetCursor(IAvnCursor *cursor) override;
+
+ virtual void UpdateCursor();
+
+ virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget **ppv) override;
+
+ virtual HRESULT CreateNativeControlHost(IAvnNativeControlHost **retOut) override;
+
+ virtual HRESULT SetBlurEnabled(bool enable) override;
+
+ virtual HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point,
+ IAvnClipboard *clipboard, IAvnDndResultCallback *cb,
+ void *sourceHandle) override;
+
+ virtual bool IsDialog();
+
+ id GetWindowProtocol ();
+
+protected:
+ virtual NSWindowStyleMask GetStyle();
+
+ void UpdateStyle();
+
+ virtual void OnInitialiseNSWindow ();
+
+private:
+ void CreateNSWindow (bool isDialog);
+ void CleanNSWindow ();
+ void InitialiseNSWindow ();
+
+ NSCursor *cursor;
+ ComPtr _glContext;
+ bool hasPosition;
+ NSSize lastSize;
+ NSSize lastMinSize;
+ NSSize lastMaxSize;
+ AvnMenu* lastMenu;
+ bool _inResize;
+
+protected:
+ AvnPoint lastPositionSet;
+ AutoFitContentView *StandardContainer;
+ bool _shown;
+
+public:
+ NSObject *renderTarget;
+ NSWindow * Window;
+ ComPtr BaseEvents;
+ AvnView *View;
+};
+
+#endif //AVALONIA_NATIVE_OSX_WINDOWBASEIMPL_H
diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
new file mode 100644
index 0000000000..6dc59ae4d8
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
@@ -0,0 +1,618 @@
+//
+// Created by Dan Walmsley on 04/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#import
+#include "common.h"
+#include "AvnView.h"
+#include "menu.h"
+#include "automation.h"
+#include "cursor.h"
+#include "ResizeScope.h"
+#include "AutoFitContentView.h"
+#import "WindowProtocol.h"
+#import "WindowInterfaces.h"
+#include "WindowBaseImpl.h"
+
+
+WindowBaseImpl::~WindowBaseImpl() {
+ View = nullptr;
+ Window = nullptr;
+}
+
+WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl) {
+ _shown = false;
+ _inResize = false;
+ BaseEvents = events;
+ _glContext = gl;
+ renderTarget = [[IOSurfaceRenderTarget alloc] initWithOpenGlContext:gl];
+ View = [[AvnView alloc] initWithParent:this];
+ StandardContainer = [[AutoFitContentView new] initWithContent:View];
+
+ lastPositionSet = { 0, 0 };
+ hasPosition = false;
+ lastSize = NSSize { 100, 100 };
+ lastMaxSize = NSSize { CGFLOAT_MAX, CGFLOAT_MAX};
+ lastMinSize = NSSize { 0, 0 };
+
+ Window = nullptr;
+ lastMenu = nullptr;
+}
+
+HRESULT WindowBaseImpl::ObtainNSViewHandle(void **ret) {
+ START_COM_CALL;
+
+ if (ret == nullptr) {
+ return E_POINTER;
+ }
+
+ *ret = (__bridge void *) View;
+
+ return S_OK;
+}
+
+HRESULT WindowBaseImpl::ObtainNSViewHandleRetained(void **ret) {
+ START_COM_CALL;
+
+ if (ret == nullptr) {
+ return E_POINTER;
+ }
+
+ *ret = (__bridge_retained void *) View;
+
+ return S_OK;
+}
+
+NSWindow *WindowBaseImpl::GetNSWindow() {
+ return Window;
+}
+
+NSView *WindowBaseImpl::GetNSView() {
+ return View;
+}
+
+HRESULT WindowBaseImpl::ObtainNSWindowHandleRetained(void **ret) {
+ START_COM_CALL;
+
+ if (ret == nullptr) {
+ return E_POINTER;
+ }
+
+ *ret = (__bridge_retained void *) Window;
+
+ return S_OK;
+}
+
+HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ CreateNSWindow(isDialog);
+ InitialiseNSWindow();
+
+ if(hasPosition)
+ {
+ SetPosition(lastPositionSet);
+ } else
+ {
+ [Window center];
+ }
+
+ UpdateStyle();
+
+ if (ShouldTakeFocusOnShow() && activate) {
+ [Window orderFront:Window];
+ [Window makeKeyAndOrderFront:Window];
+ [Window makeFirstResponder:View];
+ [NSApp activateIgnoringOtherApps:YES];
+ } else {
+ [Window orderFront:Window];
+ }
+
+ _shown = true;
+
+ return S_OK;
+ }
+}
+
+bool WindowBaseImpl::IsShown ()
+{
+ return _shown;
+}
+
+bool WindowBaseImpl::ShouldTakeFocusOnShow() {
+ return true;
+}
+
+HRESULT WindowBaseImpl::ObtainNSWindowHandle(void **ret) {
+ START_COM_CALL;
+
+ if (ret == nullptr) {
+ return E_POINTER;
+ }
+
+ *ret = (__bridge void *) Window;
+
+ return S_OK;
+}
+
+HRESULT WindowBaseImpl::Hide() {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (Window != nullptr) {
+ [Window orderOut:Window];
+
+ [GetWindowProtocol() restoreParentWindow];
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::Activate() {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (Window != nullptr) {
+ [Window makeKeyAndOrderFront:nil];
+ [NSApp activateIgnoringOtherApps:YES];
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT WindowBaseImpl::SetTopMost(bool value) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ [Window setLevel:value ? NSFloatingWindowLevel : NSNormalWindowLevel];
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::Close() {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (Window != nullptr) {
+ auto window = Window;
+ Window = nullptr;
+
+ try {
+ // Seems to throw sometimes on application exit.
+ [window close];
+ }
+ catch (NSException *) {}
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::GetClientSize(AvnSize *ret) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (ret == nullptr)
+ return E_POINTER;
+
+ ret->Width = lastSize.width;
+ ret->Height = lastSize.height;
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::GetFrameSize(AvnSize *ret) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (ret == nullptr)
+ return E_POINTER;
+
+ if(Window != nullptr){
+ auto frame = [Window frame];
+ ret->Width = frame.size.width;
+ ret->Height = frame.size.height;
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::GetScaling(double *ret) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (ret == nullptr)
+ return E_POINTER;
+
+ if (Window == nullptr) {
+ *ret = 1;
+ return S_OK;
+ }
+
+ *ret = [Window backingScaleFactor];
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::SetMinMaxSize(AvnSize minSize, AvnSize maxSize) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ lastMinSize = ToNSSize(minSize);
+ lastMaxSize = ToNSSize(maxSize);
+
+ if(Window != nullptr) {
+ [Window setContentMinSize:lastMinSize];
+ [Window setContentMaxSize:lastMaxSize];
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::Resize(double x, double y, AvnPlatformResizeReason reason) {
+ if (_inResize) {
+ return S_OK;
+ }
+
+ _inResize = true;
+
+ START_COM_CALL;
+ auto resizeBlock = ResizeScope(View, reason);
+
+ @autoreleasepool {
+ auto maxSize = lastMaxSize;
+ auto minSize = lastMinSize;
+
+ if (x < minSize.width) {
+ x = minSize.width;
+ }
+
+ if (y < minSize.height) {
+ y = minSize.height;
+ }
+
+ if (x > maxSize.width) {
+ x = maxSize.width;
+ }
+
+ if (y > maxSize.height) {
+ y = maxSize.height;
+ }
+
+ @try {
+ lastSize = NSSize {x, y};
+
+ if (!_shown) {
+ BaseEvents->Resized(AvnSize{x, y}, reason);
+ }
+
+ if(Window != nullptr) {
+ [Window setContentSize:lastSize];
+ [Window invalidateShadow];
+ }
+ }
+ @finally {
+ _inResize = false;
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::Invalidate(__attribute__((unused)) AvnRect rect) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ [View setNeedsDisplayInRect:[View frame]];
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::SetMainMenu(IAvnMenu *menu) {
+ START_COM_CALL;
+
+ auto nativeMenu = dynamic_cast(menu);
+
+ lastMenu = nativeMenu->GetNative();
+
+ if(Window != nullptr) {
+ [GetWindowProtocol() applyMenu:lastMenu];
+
+ if ([Window isKeyWindow]) {
+ [GetWindowProtocol() showWindowMenuWithAppMenu];
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT WindowBaseImpl::BeginMoveDrag() {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ auto lastEvent = [View lastMouseDownEvent];
+
+ if (lastEvent == nullptr) {
+ return S_OK;
+ }
+
+ [Window performWindowDragWithEvent:lastEvent];
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::BeginResizeDrag(__attribute__((unused)) AvnWindowEdge edge) {
+ START_COM_CALL;
+
+ return S_OK;
+}
+
+HRESULT WindowBaseImpl::GetPosition(AvnPoint *ret) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (ret == nullptr) {
+ return E_POINTER;
+ }
+
+ if(Window != nullptr) {
+ auto frame = [Window frame];
+
+ ret->X = frame.origin.x;
+ ret->Y = frame.origin.y + frame.size.height;
+
+ *ret = ConvertPointY(*ret);
+ } else
+ {
+ *ret = lastPositionSet;
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::SetPosition(AvnPoint point) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ lastPositionSet = point;
+ hasPosition = true;
+
+ if(Window != nullptr) {
+ [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(point))];
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::PointToClient(AvnPoint point, AvnPoint *ret) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (ret == nullptr) {
+ return E_POINTER;
+ }
+
+ point = ConvertPointY(point);
+ NSRect convertRect = [Window convertRectFromScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)];
+ auto viewPoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y);
+
+ *ret = [View translateLocalPoint:ToAvnPoint(viewPoint)];
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::PointToScreen(AvnPoint point, AvnPoint *ret) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (ret == nullptr) {
+ return E_POINTER;
+ }
+
+ auto cocoaViewPoint = ToNSPoint([View translateLocalPoint:point]);
+ NSRect convertRect = [Window convertRectToScreen:NSMakeRect(cocoaViewPoint.x, cocoaViewPoint.y, 0.0, 0.0)];
+ auto cocoaScreenPoint = NSPointFromCGPoint(NSMakePoint(convertRect.origin.x, convertRect.origin.y));
+ *ret = ConvertPointY(ToAvnPoint(cocoaScreenPoint));
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowBaseImpl::ThreadSafeSetSwRenderedFrame(AvnFramebuffer *fb, IUnknown *dispose) {
+ START_COM_CALL;
+
+ [View setSwRenderedFrame:fb dispose:dispose];
+ return S_OK;
+}
+
+HRESULT WindowBaseImpl::SetCursor(IAvnCursor *cursor) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ Cursor *avnCursor = dynamic_cast(cursor);
+ this->cursor = avnCursor->GetNative();
+ UpdateCursor();
+
+ if (avnCursor->IsHidden()) {
+ [NSCursor hide];
+ } else {
+ [NSCursor unhide];
+ }
+
+ return S_OK;
+ }
+}
+
+void WindowBaseImpl::UpdateCursor() {
+ if (cursor != nil) {
+ [cursor set];
+ }
+}
+
+HRESULT WindowBaseImpl::CreateGlRenderTarget(IAvnGlSurfaceRenderTarget **ppv) {
+ START_COM_CALL;
+
+ if (View == NULL)
+ return E_FAIL;
+ *ppv = [renderTarget createSurfaceRenderTarget];
+ return static_cast(*ppv == nil ? E_FAIL : S_OK);
+}
+
+HRESULT WindowBaseImpl::CreateNativeControlHost(IAvnNativeControlHost **retOut) {
+ START_COM_CALL;
+
+ if (View == NULL)
+ return E_FAIL;
+ *retOut = ::CreateNativeControlHost(View);
+ return S_OK;
+}
+
+HRESULT WindowBaseImpl::SetBlurEnabled(bool enable) {
+ START_COM_CALL;
+
+ [StandardContainer ShowBlur:enable];
+
+ return S_OK;
+}
+
+HRESULT WindowBaseImpl::BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point, IAvnClipboard *clipboard, IAvnDndResultCallback *cb, void *sourceHandle) {
+ START_COM_CALL;
+
+ auto item = TryGetPasteboardItem(clipboard);
+ [item setString:@"" forType:GetAvnCustomDataType()];
+ if (item == nil)
+ return E_INVALIDARG;
+ if (View == NULL)
+ return E_FAIL;
+
+ auto nsevent = [NSApp currentEvent];
+ auto nseventType = [nsevent type];
+
+ // If current event isn't a mouse one (probably due to malfunctioning user app)
+ // attempt to forge a new one
+ if (!((nseventType >= NSEventTypeLeftMouseDown && nseventType <= NSEventTypeMouseExited)
+ || (nseventType >= NSEventTypeOtherMouseDown && nseventType <= NSEventTypeOtherMouseDragged))) {
+ NSRect convertRect = [Window convertRectToScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)];
+ auto nspoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y);
+ CGPoint cgpoint = NSPointToCGPoint(nspoint);
+ auto cgevent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, cgpoint, kCGMouseButtonLeft);
+ nsevent = [NSEvent eventWithCGEvent:cgevent];
+ CFRelease(cgevent);
+ }
+
+ auto dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:item];
+
+ auto dragItemImage = [NSImage imageNamed:NSImageNameMultipleDocuments];
+ NSRect dragItemRect = {(float) point.X, (float) point.Y, [dragItemImage size].width, [dragItemImage size].height};
+ [dragItem setDraggingFrame:dragItemRect contents:dragItemImage];
+
+ int op = 0;
+ int ieffects = (int) effects;
+ if ((ieffects & (int) AvnDragDropEffects::Copy) != 0)
+ op |= NSDragOperationCopy;
+ if ((ieffects & (int) AvnDragDropEffects::Link) != 0)
+ op |= NSDragOperationLink;
+ if ((ieffects & (int) AvnDragDropEffects::Move) != 0)
+ op |= NSDragOperationMove;
+ [View beginDraggingSessionWithItems:@[dragItem] event:nsevent
+ source:CreateDraggingSource((NSDragOperation) op, cb, sourceHandle)];
+ return S_OK;
+}
+
+bool WindowBaseImpl::IsDialog() {
+ return false;
+}
+
+NSWindowStyleMask WindowBaseImpl::GetStyle() {
+ return NSWindowStyleMaskBorderless;
+}
+
+void WindowBaseImpl::UpdateStyle() {
+ [Window setStyleMask:GetStyle()];
+}
+
+void WindowBaseImpl::CleanNSWindow() {
+ if(Window != nullptr) {
+ [GetWindowProtocol() disconnectParent];
+ [Window close];
+ Window = nullptr;
+ }
+}
+
+void WindowBaseImpl::CreateNSWindow(bool isDialog) {
+ if (isDialog) {
+ if (![Window isKindOfClass:[AvnPanel class]]) {
+ CleanNSWindow();
+
+ Window = [[AvnPanel alloc] initWithParent:this contentRect:NSRect{0, 0, lastSize} styleMask:GetStyle()];
+ }
+ } else {
+ if (![Window isKindOfClass:[AvnWindow class]]) {
+ CleanNSWindow();
+
+ Window = [[AvnWindow alloc] initWithParent:this contentRect:NSRect{0, 0, lastSize} styleMask:GetStyle()];
+ }
+ }
+}
+
+void WindowBaseImpl::OnInitialiseNSWindow()
+{
+
+}
+
+void WindowBaseImpl::InitialiseNSWindow() {
+ if(Window != nullptr) {
+ [Window setContentView:StandardContainer];
+ [Window setStyleMask:NSWindowStyleMaskBorderless];
+ [Window setBackingType:NSBackingStoreBuffered];
+
+ [Window setContentSize:lastSize];
+ [Window setContentMinSize:lastMinSize];
+ [Window setContentMaxSize:lastMaxSize];
+
+ [Window setOpaque:false];
+
+ [Window invalidateShadow];
+
+ if (lastMenu != nullptr) {
+ [GetWindowProtocol() applyMenu:lastMenu];
+
+ if ([Window isKeyWindow]) {
+ [GetWindowProtocol() showWindowMenuWithAppMenu];
+ }
+ }
+
+ OnInitialiseNSWindow();
+ }
+}
+
+id WindowBaseImpl::GetWindowProtocol() {
+ if(Window == nullptr)
+ {
+ return nullptr;
+ }
+
+ return (id ) Window;
+}
+
+extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl)
+{
+ @autoreleasepool
+ {
+ IAvnWindow* ptr = (IAvnWindow*)new WindowImpl(events, gl);
+ return ptr;
+ }
+}
diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h
new file mode 100644
index 0000000000..db19497b29
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/WindowImpl.h
@@ -0,0 +1,101 @@
+//
+// Created by Dan Walmsley on 04/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#ifndef AVALONIA_NATIVE_OSX_WINDOWIMPL_H
+#define AVALONIA_NATIVE_OSX_WINDOWIMPL_H
+
+#import "WindowBaseImpl.h"
+#include "IWindowStateChanged.h"
+
+class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged
+{
+private:
+ bool _canResize;
+ bool _fullScreenActive;
+ SystemDecorations _decorations;
+ AvnWindowState _lastWindowState;
+ AvnWindowState _actualWindowState;
+ bool _inSetWindowState;
+ NSRect _preZoomSize;
+ bool _transitioningWindowState;
+ bool _isClientAreaExtended;
+ bool _isDialog;
+ AvnExtendClientAreaChromeHints _extendClientHints;
+
+ FORWARD_IUNKNOWN()
+BEGIN_INTERFACE_MAP()
+ INHERIT_INTERFACE_MAP(WindowBaseImpl)
+ INTERFACE_MAP_ENTRY(IAvnWindow, IID_IAvnWindow)
+ END_INTERFACE_MAP()
+ virtual ~WindowImpl()
+ {
+ }
+
+ ComPtr WindowEvents;
+
+ WindowImpl(IAvnWindowEvents* events, IAvnGlContext* gl);
+
+ void HideOrShowTrafficLights ();
+
+ virtual HRESULT Show (bool activate, bool isDialog) override;
+
+ virtual HRESULT SetEnabled (bool enable) override;
+
+ virtual HRESULT SetParent (IAvnWindow* parent) override;
+
+ void StartStateTransition () override ;
+
+ void EndStateTransition () override ;
+
+ SystemDecorations Decorations () override ;
+
+ AvnWindowState WindowState () override ;
+
+ void WindowStateChanged () override ;
+
+ bool UndecoratedIsMaximized ();
+
+ bool IsZoomed ();
+
+ void DoZoom();
+
+ virtual HRESULT SetCanResize(bool value) override;
+
+ virtual HRESULT SetDecorations(SystemDecorations value) override;
+
+ virtual HRESULT SetTitle (char* utf8title) override;
+
+ virtual HRESULT SetTitleBarColor(AvnColor color) override;
+
+ virtual HRESULT GetWindowState (AvnWindowState*ret) override;
+
+ virtual HRESULT TakeFocusFromChildren () override;
+
+ virtual HRESULT SetExtendClientArea (bool enable) override;
+
+ virtual HRESULT SetExtendClientAreaHints (AvnExtendClientAreaChromeHints hints) override;
+
+ virtual HRESULT GetExtendTitleBarHeight (double*ret) override;
+
+ virtual HRESULT SetExtendTitleBarHeight (double value) override;
+
+ void EnterFullScreenMode ();
+
+ void ExitFullScreenMode ();
+
+ virtual HRESULT SetWindowState (AvnWindowState state) override;
+
+ virtual bool IsDialog() override;
+
+ virtual void OnInitialiseNSWindow() override;
+
+protected:
+ virtual NSWindowStyleMask GetStyle() override;
+
+private:
+ NSString *_lastTitle;
+};
+
+#endif //AVALONIA_NATIVE_OSX_WINDOWIMPL_H
diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm
new file mode 100644
index 0000000000..d96fe717ab
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm
@@ -0,0 +1,554 @@
+//
+// Created by Dan Walmsley on 04/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#import
+#include "AutoFitContentView.h"
+#include "AvnView.h"
+#include "automation.h"
+#include "WindowProtocol.h"
+
+WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBaseImpl(events, gl) {
+ _isClientAreaExtended = false;
+ _extendClientHints = AvnDefaultChrome;
+ _fullScreenActive = false;
+ _canResize = true;
+ _decorations = SystemDecorationsFull;
+ _transitioningWindowState = false;
+ _inSetWindowState = false;
+ _lastWindowState = Normal;
+ _actualWindowState = Normal;
+ _lastTitle = @"";
+ WindowEvents = events;
+}
+
+void WindowImpl::HideOrShowTrafficLights() {
+ if (Window == nil) {
+ return;
+ }
+
+ for (id subview in Window.contentView.superview.subviews) {
+ if ([subview isKindOfClass:NSClassFromString(@"NSTitlebarContainerView")]) {
+ NSView *titlebarView = [subview subviews][0];
+ for (id button in titlebarView.subviews) {
+ if ([button isKindOfClass:[NSButton class]]) {
+ if (_isClientAreaExtended) {
+ auto wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
+
+ [button setHidden:!wantsChrome];
+ } else {
+ [button setHidden:(_decorations != SystemDecorationsFull)];
+ }
+
+ [button setWantsLayer:true];
+ }
+ }
+ }
+ }
+}
+
+void WindowImpl::OnInitialiseNSWindow(){
+ [GetWindowProtocol() setCanBecomeKeyWindow:true];
+ [Window disableCursorRects];
+ [Window setTabbingMode:NSWindowTabbingModeDisallowed];
+ [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+
+ [Window setTitle:_lastTitle];
+
+ if(_isClientAreaExtended)
+ {
+ [GetWindowProtocol() setIsExtended:true];
+ SetExtendClientArea(true);
+ }
+}
+
+HRESULT WindowImpl::Show(bool activate, bool isDialog) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ _isDialog = isDialog;
+
+ WindowBaseImpl::Show(activate, isDialog);
+
+ HideOrShowTrafficLights();
+
+ return SetWindowState(_lastWindowState);
+ }
+}
+
+HRESULT WindowImpl::SetEnabled(bool enable) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ [GetWindowProtocol() setEnabled:enable];
+ return S_OK;
+ }
+}
+
+HRESULT WindowImpl::SetParent(IAvnWindow *parent) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (parent == nullptr)
+ return E_POINTER;
+
+ auto cparent = dynamic_cast(parent);
+ if (cparent == nullptr)
+ return E_INVALIDARG;
+
+ // If one tries to show a child window with a minimized parent window, then the parent window will be
+ // restored but macOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive
+ // state. Detect this and explicitly restore the parent window ourselves to avoid this situation.
+ if (cparent->WindowState() == Minimized)
+ cparent->SetWindowState(Normal);
+
+ [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
+ [cparent->Window addChildWindow:Window ordered:NSWindowAbove];
+
+ UpdateStyle();
+
+ return S_OK;
+ }
+}
+
+void WindowImpl::StartStateTransition() {
+ _transitioningWindowState = true;
+}
+
+void WindowImpl::EndStateTransition() {
+ _transitioningWindowState = false;
+}
+
+SystemDecorations WindowImpl::Decorations() {
+ return _decorations;
+}
+
+AvnWindowState WindowImpl::WindowState() {
+ return _lastWindowState;
+}
+
+void WindowImpl::WindowStateChanged() {
+ if (_shown && !_inSetWindowState && !_transitioningWindowState) {
+ AvnWindowState state;
+ GetWindowState(&state);
+
+ if (_lastWindowState != state) {
+ if (_isClientAreaExtended) {
+ if (_lastWindowState == FullScreen) {
+ // we exited fs.
+ if (_extendClientHints & AvnOSXThickTitleBar) {
+ Window.toolbar = [NSToolbar new];
+ Window.toolbar.showsBaselineSeparator = false;
+ }
+
+ [Window setTitlebarAppearsTransparent:true];
+
+ [StandardContainer setFrameSize:StandardContainer.frame.size];
+ } else if (state == FullScreen) {
+ // we entered fs.
+ if (_extendClientHints & AvnOSXThickTitleBar) {
+ Window.toolbar = nullptr;
+ }
+
+ [Window setTitlebarAppearsTransparent:false];
+
+ [StandardContainer setFrameSize:StandardContainer.frame.size];
+ }
+ }
+
+ _lastWindowState = state;
+ _actualWindowState = state;
+ WindowEvents->WindowStateChanged(state);
+ }
+ }
+}
+
+bool WindowImpl::UndecoratedIsMaximized() {
+ auto windowSize = [Window frame];
+ auto available = [Window screen].visibleFrame;
+ return CGRectEqualToRect(windowSize, available);
+}
+
+bool WindowImpl::IsZoomed() {
+ return _decorations == SystemDecorationsFull ? [Window isZoomed] : UndecoratedIsMaximized();
+}
+
+void WindowImpl::DoZoom() {
+ switch (_decorations) {
+ case SystemDecorationsNone:
+ case SystemDecorationsBorderOnly:
+ [Window setFrame:[Window screen].visibleFrame display:true];
+ break;
+
+
+ case SystemDecorationsFull:
+ [Window performZoom:Window];
+ break;
+ }
+}
+
+HRESULT WindowImpl::SetCanResize(bool value) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ _canResize = value;
+ UpdateStyle();
+ return S_OK;
+ }
+}
+
+HRESULT WindowImpl::SetDecorations(SystemDecorations value) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ auto currentWindowState = _lastWindowState;
+ _decorations = value;
+
+ if (_fullScreenActive) {
+ return S_OK;
+ }
+
+ UpdateStyle();
+
+ HideOrShowTrafficLights();
+
+ switch (_decorations) {
+ case SystemDecorationsNone:
+ [Window setHasShadow:NO];
+ [Window setTitleVisibility:NSWindowTitleHidden];
+ [Window setTitlebarAppearsTransparent:YES];
+
+ if (currentWindowState == Maximized) {
+ if (!UndecoratedIsMaximized()) {
+ DoZoom();
+ }
+ }
+ break;
+
+ case SystemDecorationsBorderOnly:
+ [Window setHasShadow:YES];
+ [Window setTitleVisibility:NSWindowTitleHidden];
+ [Window setTitlebarAppearsTransparent:YES];
+
+ if (currentWindowState == Maximized) {
+ if (!UndecoratedIsMaximized()) {
+ DoZoom();
+ }
+ }
+ break;
+
+ case SystemDecorationsFull:
+ [Window setHasShadow:YES];
+ [Window setTitleVisibility:NSWindowTitleVisible];
+ [Window setTitlebarAppearsTransparent:NO];
+ [Window setTitle:_lastTitle];
+
+ if (currentWindowState == Maximized) {
+ auto newFrame = [Window contentRectForFrameRect:[Window frame]].size;
+
+ [View setFrameSize:newFrame];
+ }
+ break;
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowImpl::SetTitle(char *utf8title) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ _lastTitle = [NSString stringWithUTF8String:(const char *) utf8title];
+ [Window setTitle:_lastTitle];
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowImpl::SetTitleBarColor(AvnColor color) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ float a = (float) color.Alpha / 255.0f;
+ float r = (float) color.Red / 255.0f;
+ float g = (float) color.Green / 255.0f;
+ float b = (float) color.Blue / 255.0f;
+
+ auto nscolor = [NSColor colorWithSRGBRed:r green:g blue:b alpha:a];
+
+ // Based on the titlebar color we have to choose either light or dark
+ // OSX doesnt let you set a foreground color for titlebar.
+ if ((r * 0.299 + g * 0.587 + b * 0.114) > 186.0f / 255.0f) {
+ [Window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]];
+ } else {
+ [Window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]];
+ }
+
+ [Window setTitlebarAppearsTransparent:true];
+ [Window setBackgroundColor:nscolor];
+ }
+
+ return S_OK;
+}
+
+HRESULT WindowImpl::GetWindowState(AvnWindowState *ret) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (ret == nullptr) {
+ return E_POINTER;
+ }
+
+ if (([Window styleMask] & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen) {
+ *ret = FullScreen;
+ return S_OK;
+ }
+
+ if ([Window isMiniaturized]) {
+ *ret = Minimized;
+ return S_OK;
+ }
+
+ if (IsZoomed()) {
+ *ret = Maximized;
+ return S_OK;
+ }
+
+ *ret = Normal;
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowImpl::TakeFocusFromChildren() {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (Window == nil)
+ return S_OK;
+ if ([Window isKeyWindow])
+ [Window makeFirstResponder:View];
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowImpl::SetExtendClientArea(bool enable) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ _isClientAreaExtended = enable;
+
+ if(Window != nullptr) {
+ if (enable) {
+ Window.titleVisibility = NSWindowTitleHidden;
+
+ [Window setTitlebarAppearsTransparent:true];
+
+ auto wantsTitleBar = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
+
+ if (wantsTitleBar) {
+ [StandardContainer ShowTitleBar:true];
+ } else {
+ [StandardContainer ShowTitleBar:false];
+ }
+
+ if (_extendClientHints & AvnOSXThickTitleBar) {
+ Window.toolbar = [NSToolbar new];
+ Window.toolbar.showsBaselineSeparator = false;
+ } else {
+ Window.toolbar = nullptr;
+ }
+ } else {
+ Window.titleVisibility = NSWindowTitleVisible;
+ Window.toolbar = nullptr;
+ [Window setTitlebarAppearsTransparent:false];
+ View.layer.zPosition = 0;
+ }
+
+ [GetWindowProtocol() setIsExtended:enable];
+
+ HideOrShowTrafficLights();
+
+ UpdateStyle();
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowImpl::SetExtendClientAreaHints(AvnExtendClientAreaChromeHints hints) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ _extendClientHints = hints;
+
+ SetExtendClientArea(_isClientAreaExtended);
+ return S_OK;
+ }
+}
+
+HRESULT WindowImpl::GetExtendTitleBarHeight(double *ret) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ if (ret == nullptr) {
+ return E_POINTER;
+ }
+
+ *ret = [GetWindowProtocol() getExtendedTitleBarHeight];
+
+ return S_OK;
+ }
+}
+
+HRESULT WindowImpl::SetExtendTitleBarHeight(double value) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ [StandardContainer SetTitleBarHeightHint:value];
+ return S_OK;
+ }
+}
+
+void WindowImpl::EnterFullScreenMode() {
+ _fullScreenActive = true;
+
+ [Window setTitle:_lastTitle];
+ [Window toggleFullScreen:nullptr];
+}
+
+void WindowImpl::ExitFullScreenMode() {
+ [Window toggleFullScreen:nullptr];
+
+ _fullScreenActive = false;
+
+ SetDecorations(_decorations);
+}
+
+HRESULT WindowImpl::SetWindowState(AvnWindowState state) {
+ START_COM_CALL;
+
+ @autoreleasepool {
+ auto currentState = _actualWindowState;
+ _lastWindowState = state;
+
+ if (Window == nullptr) {
+ return S_OK;
+ }
+
+ if (_actualWindowState == state) {
+ return S_OK;
+ }
+
+ _inSetWindowState = true;
+
+ if (currentState == Normal) {
+ _preZoomSize = [Window frame];
+ }
+
+ if (_shown) {
+ switch (state) {
+ case Maximized:
+ if (currentState == FullScreen) {
+ ExitFullScreenMode();
+ }
+
+ lastPositionSet.X = 0;
+ lastPositionSet.Y = 0;
+
+ if ([Window isMiniaturized]) {
+ [Window deminiaturize:Window];
+ }
+
+ if (!IsZoomed()) {
+ DoZoom();
+ }
+ break;
+
+ case Minimized:
+ if (currentState == FullScreen) {
+ ExitFullScreenMode();
+ } else {
+ [Window miniaturize:Window];
+ }
+ break;
+
+ case FullScreen:
+ if ([Window isMiniaturized]) {
+ [Window deminiaturize:Window];
+ }
+
+ EnterFullScreenMode();
+ break;
+
+ case Normal:
+ if ([Window isMiniaturized]) {
+ [Window deminiaturize:Window];
+ }
+
+ if (currentState == FullScreen) {
+ ExitFullScreenMode();
+ }
+
+ if (IsZoomed()) {
+ if (_decorations == SystemDecorationsFull) {
+ DoZoom();
+ } else {
+ [Window setFrame:_preZoomSize display:true];
+ auto newFrame = [Window contentRectForFrameRect:[Window frame]].size;
+
+ [View setFrameSize:newFrame];
+ }
+
+ }
+ break;
+ }
+
+ _actualWindowState = _lastWindowState;
+ WindowEvents->WindowStateChanged(_actualWindowState);
+ }
+
+
+ _inSetWindowState = false;
+
+ return S_OK;
+ }
+}
+
+bool WindowImpl::IsDialog() {
+ return _isDialog;
+}
+
+NSWindowStyleMask WindowImpl::GetStyle() {
+ unsigned long s = this->_isDialog ? NSWindowStyleMaskDocModalWindow : NSWindowStyleMaskBorderless;
+
+ switch (_decorations) {
+ case SystemDecorationsNone:
+ s = s | NSWindowStyleMaskFullSizeContentView;
+ break;
+
+ case SystemDecorationsBorderOnly:
+ s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView;
+ break;
+
+ case SystemDecorationsFull:
+ s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskBorderless;
+
+ if (_canResize) {
+ s = s | NSWindowStyleMaskResizable;
+ }
+ break;
+ }
+
+ if ([Window parentWindow] == nullptr) {
+ s |= NSWindowStyleMaskMiniaturizable;
+ }
+
+ if (_isClientAreaExtended) {
+ s |= NSWindowStyleMaskFullSizeContentView | NSWindowStyleMaskTexturedBackground;
+ }
+ return s;
+}
diff --git a/native/Avalonia.Native/src/OSX/WindowInterfaces.h b/native/Avalonia.Native/src/OSX/WindowInterfaces.h
new file mode 100644
index 0000000000..6e6d62e85e
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/WindowInterfaces.h
@@ -0,0 +1,17 @@
+//
+// Created by Dan Walmsley on 06/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#import
+#import
+#include "WindowProtocol.h"
+#include "WindowBaseImpl.h"
+
+@interface AvnWindow : NSWindow
+-(AvnWindow* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask;
+@end
+
+@interface AvnPanel : NSPanel
+-(AvnPanel* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask;
+@end
\ No newline at end of file
diff --git a/native/Avalonia.Native/src/OSX/WindowProtocol.h b/native/Avalonia.Native/src/OSX/WindowProtocol.h
new file mode 100644
index 0000000000..0e5c5869e7
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/WindowProtocol.h
@@ -0,0 +1,27 @@
+//
+// Created by Dan Walmsley on 06/05/2022.
+// Copyright (c) 2022 Avalonia. All rights reserved.
+//
+
+#pragma once
+
+#import
+
+@class AvnMenu;
+
+@protocol AvnWindowProtocol
+-(void) pollModalSession: (NSModalSession _Nonnull) session;
+-(void) restoreParentWindow;
+-(bool) shouldTryToHandleEvents;
+-(void) setEnabled: (bool) enable;
+-(void) showAppMenuOnly;
+-(void) showWindowMenuWithAppMenu;
+-(void) applyMenu:(AvnMenu* _Nullable)menu;
+
+-(double) getExtendedTitleBarHeight;
+-(void) setIsExtended:(bool)value;
+-(void) disconnectParent;
+-(bool) isDialog;
+
+-(void) setCanBecomeKeyWindow:(bool)value;
+@end
diff --git a/native/Avalonia.Native/src/OSX/app.mm b/native/Avalonia.Native/src/OSX/app.mm
index 79175d9ff1..14f1f6888c 100644
--- a/native/Avalonia.Native/src/OSX/app.mm
+++ b/native/Avalonia.Native/src/OSX/app.mm
@@ -73,22 +73,15 @@ ComPtr _events;
_isHandlingSendEvent = true;
@try {
[super sendEvent: event];
+ if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand))
+ {
+ [[self keyWindow] sendEvent:event];
+ }
+
} @finally {
_isHandlingSendEvent = oldHandling;
}
}
-
-// This is needed for certain embedded controls
-- (BOOL) isHandlingSendEvent
-{
- return _isHandlingSendEvent;
-}
-
-- (void)setHandlingSendEvent:(BOOL)handlingSendEvent
-{
- _isHandlingSendEvent = handlingSendEvent;
-}
-
@end
extern void InitializeAvnApp(IAvnApplicationEvents* events)
diff --git a/native/Avalonia.Native/src/OSX/automation.h b/native/Avalonia.Native/src/OSX/automation.h
index 4a12a965fd..367df3619d 100644
--- a/native/Avalonia.Native/src/OSX/automation.h
+++ b/native/Avalonia.Native/src/OSX/automation.h
@@ -1,6 +1,6 @@
-#import
-#include "window.h"
+#pragma once
+#import
NS_ASSUME_NONNULL_BEGIN
class IAvnAutomationPeer;
diff --git a/native/Avalonia.Native/src/OSX/automation.mm b/native/Avalonia.Native/src/OSX/automation.mm
index 7d697140c2..d0c8d7a9db 100644
--- a/native/Avalonia.Native/src/OSX/automation.mm
+++ b/native/Avalonia.Native/src/OSX/automation.mm
@@ -1,7 +1,8 @@
#include "common.h"
#include "automation.h"
#include "AvnString.h"
-#include "window.h"
+#include "INSWindowHolder.h"
+#include "AvnView.h"
@interface AvnAccessibilityElement (Events)
- (void) raiseChildrenChanged;
diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h
index 9186d9e15a..a90a235b9d 100644
--- a/native/Avalonia.Native/src/OSX/common.h
+++ b/native/Avalonia.Native/src/OSX/common.h
@@ -27,7 +27,7 @@ extern IAvnMenuItem* CreateAppMenuItem();
extern IAvnMenuItem* CreateAppMenuItemSeparator();
extern IAvnApplicationCommands* CreateApplicationCommands();
extern IAvnNativeControlHost* CreateNativeControlHost(NSView* parent);
-extern void SetAppMenu (NSString* appName, IAvnMenu* appMenu);
+extern void SetAppMenu(IAvnMenu *menu);
extern void SetServicesMenu (IAvnMenu* menu);
extern IAvnMenu* GetAppMenu ();
extern NSMenuItem* GetAppMenuItem ();
@@ -38,7 +38,6 @@ extern NSPoint ToNSPoint (AvnPoint p);
extern NSRect ToNSRect (AvnRect r);
extern AvnPoint ToAvnPoint (NSPoint p);
extern AvnPoint ConvertPointY (AvnPoint p);
-extern CGFloat PrimaryDisplayHeight();
extern NSSize ToNSSize (AvnSize s);
#ifdef DEBUG
#define NSDebugLog(...) NSLog(__VA_ARGS__)
diff --git a/native/Avalonia.Native/src/OSX/cursor.mm b/native/Avalonia.Native/src/OSX/cursor.mm
index dc38294a18..8638a03531 100644
--- a/native/Avalonia.Native/src/OSX/cursor.mm
+++ b/native/Avalonia.Native/src/OSX/cursor.mm
@@ -1,6 +1,5 @@
#include "common.h"
#include "cursor.h"
-#include
+
\ No newline at end of file
diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
index d1b657722c..2b45ac1508 100644
--- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
+++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
@@ -6,7 +6,7 @@
true
-
+
true
https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json
7.0.0-*
@@ -22,12 +22,11 @@
-
+
-
diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs
index 4b81935452..4464413e63 100644
--- a/samples/ControlCatalog.NetCore/Program.cs
+++ b/samples/ControlCatalog.NetCore/Program.cs
@@ -117,7 +117,6 @@ namespace ControlCatalog.NetCore
EnableMultitouch = true
})
.UseSkia()
- .UseManagedSystemDialogs()
.AfterSetup(builder =>
{
builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()
diff --git a/samples/ControlCatalog.NetCore/rd.xml b/samples/ControlCatalog.NetCore/rd.xml
deleted file mode 100644
index 27db7f34ca..0000000000
--- a/samples/ControlCatalog.NetCore/rd.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj b/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj
index 12d1d5645e..513ac44f83 100644
--- a/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj
+++ b/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj
@@ -7,10 +7,10 @@
True
iossimulator-x64
-
+
-
+
\ No newline at end of file
diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs
index 866fb8632a..7ebb87094a 100644
--- a/samples/ControlCatalog/App.xaml.cs
+++ b/samples/ControlCatalog/App.xaml.cs
@@ -18,6 +18,16 @@ namespace ControlCatalog
DataContext = new ApplicationViewModel();
}
+ public static readonly StyleInclude ColorPickerFluent = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
+ {
+ Source = new Uri("avares://Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml")
+ };
+
+ public static readonly StyleInclude ColorPickerDefault = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
+ {
+ Source = new Uri("avares://Avalonia.Controls.ColorPicker/Themes/Default/Default.xaml")
+ };
+
public static readonly StyleInclude DataGridFluent = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
{
Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml")
@@ -69,7 +79,8 @@ namespace ControlCatalog
public override void Initialize()
{
Styles.Insert(0, Fluent);
- Styles.Insert(1, DataGridFluent);
+ Styles.Insert(1, ColorPickerFluent);
+ Styles.Insert(2, DataGridFluent);
AvaloniaXamlLoader.Load(this);
}
diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj
index c0e24357ca..bce924a3f2 100644
--- a/samples/ControlCatalog/ControlCatalog.csproj
+++ b/samples/ControlCatalog/ControlCatalog.csproj
@@ -1,7 +1,8 @@
netstandard2.0
- true
+ true
+ enable
@@ -23,7 +24,10 @@
+
+
+
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 85f278b5fa..59d724db69 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -43,6 +43,9 @@
+
+
+
diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs
index e8ea39abbb..0326946c08 100644
--- a/samples/ControlCatalog/MainView.xaml.cs
+++ b/samples/ControlCatalog/MainView.xaml.cs
@@ -49,7 +49,8 @@ namespace ControlCatalog
App.Fluent.Mode = FluentThemeMode.Light;
}
Application.Current.Styles[0] = App.Fluent;
- Application.Current.Styles[1] = App.DataGridFluent;
+ Application.Current.Styles[1] = App.ColorPickerFluent;
+ Application.Current.Styles[2] = App.DataGridFluent;
}
else if (theme == CatalogTheme.FluentDark)
{
@@ -59,19 +60,22 @@ namespace ControlCatalog
App.Fluent.Mode = FluentThemeMode.Dark;
}
Application.Current.Styles[0] = App.Fluent;
- Application.Current.Styles[1] = App.DataGridFluent;
+ Application.Current.Styles[1] = App.ColorPickerFluent;
+ Application.Current.Styles[2] = App.DataGridFluent;
}
else if (theme == CatalogTheme.DefaultLight)
{
App.Default.Mode = Avalonia.Themes.Default.SimpleThemeMode.Light;
Application.Current.Styles[0] = App.DefaultLight;
- Application.Current.Styles[1] = App.DataGridDefault;
+ Application.Current.Styles[1] = App.ColorPickerDefault;
+ Application.Current.Styles[2] = App.DataGridDefault;
}
else if (theme == CatalogTheme.DefaultDark)
{
App.Default.Mode = Avalonia.Themes.Default.SimpleThemeMode.Dark;
Application.Current.Styles[0] = App.DefaultDark;
- Application.Current.Styles[1] = App.DataGridDefault;
+ Application.Current.Styles[1] = App.ColorPickerDefault;
+ Application.Current.Styles[2] = App.DataGridDefault;
}
}
};
diff --git a/samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml b/samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml
index 2fe16ba8e3..aef96802f4 100644
--- a/samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml
+++ b/samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml
@@ -10,8 +10,7 @@
Margin="0,16,0,0"
HorizontalAlignment="Center"
Spacing="16">
-
+
None
Slide
Crossfade
+ 3D Rotation
diff --git a/samples/ControlCatalog/Pages/CarouselPage.xaml.cs b/samples/ControlCatalog/Pages/CarouselPage.xaml.cs
index 66180d4ccb..6b7707be13 100644
--- a/samples/ControlCatalog/Pages/CarouselPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/CarouselPage.xaml.cs
@@ -45,6 +45,9 @@ namespace ControlCatalog.Pages
case 2:
_carousel.PageTransition = new CrossFade(TimeSpan.FromSeconds(0.25));
break;
+ case 3:
+ _carousel.PageTransition = new Rotate3DTransition(TimeSpan.FromSeconds(0.5), _orientation.SelectedIndex == 0 ? PageSlide.SlideAxis.Horizontal : PageSlide.SlideAxis.Vertical);
+ break;
}
}
}
diff --git a/samples/ControlCatalog/Pages/ColorPickerPage.xaml b/samples/ControlCatalog/Pages/ColorPickerPage.xaml
new file mode 100644
index 0000000000..c0c83d6a35
--- /dev/null
+++ b/samples/ControlCatalog/Pages/ColorPickerPage.xaml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/ColorPickerPage.xaml.cs b/samples/ControlCatalog/Pages/ColorPickerPage.xaml.cs
new file mode 100644
index 0000000000..6e017e381f
--- /dev/null
+++ b/samples/ControlCatalog/Pages/ColorPickerPage.xaml.cs
@@ -0,0 +1,19 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+ public partial class ColorPickerPage : UserControl
+ {
+ public ColorPickerPage()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/samples/ControlCatalog/Pages/ComboBoxPage.xaml b/samples/ControlCatalog/Pages/ComboBoxPage.xaml
index 64e80a8e11..9f2fbb88f3 100644
--- a/samples/ControlCatalog/Pages/ComboBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/ComboBoxPage.xaml
@@ -86,6 +86,16 @@
+
+
+
+
+
+ Inline Items
+ Inline Item 2
+ Inline Item 3
+ Inline Item 4
+
WrapSelection
diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml b/samples/ControlCatalog/Pages/DataGridPage.xaml
index f7e3cf2441..31b4039d33 100644
--- a/samples/ControlCatalog/Pages/DataGridPage.xaml
+++ b/samples/ControlCatalog/Pages/DataGridPage.xaml
@@ -13,9 +13,22 @@
+
+
+
+
@@ -31,7 +44,9 @@
-
+
diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
index 3cadc7243a..fd908a33b6 100644
--- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
@@ -8,7 +8,6 @@ using Avalonia.Dialogs;
using Avalonia.Layout;
using Avalonia.Markup.Xaml;
#pragma warning disable 4014
-
namespace ControlCatalog.Pages
{
public class DialogsPage : UserControl
@@ -22,7 +21,7 @@ namespace ControlCatalog.Pages
string lastSelectedDirectory = null;
- List GetFilters()
+ List? GetFilters()
{
if (this.FindControl("UseFilters").IsChecked != true)
return null;
diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
index 8305d72d1f..1d42b92096 100644
--- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
+++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
@@ -53,10 +53,12 @@
UniformGrid - Horizontal
+
+
("scroller");
_scrollToLast = this.FindControl
diff --git a/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs b/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
index ee1fa6ae77..1a424bb500 100644
--- a/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
@@ -31,6 +31,19 @@ namespace ControlCatalog.ViewModels
Items.Insert(index + 1, new Item(index + 1) { Text = $"New Item {_newItemIndex++}" });
}
+ public void RemoveItem()
+ {
+ if (SelectedItem is not null)
+ {
+ Items.Remove(SelectedItem);
+ SelectedItem = null;
+ }
+ else if (Items.Count > 0)
+ {
+ Items.RemoveAt(Items.Count - 1);
+ }
+ }
+
public void RandomizeHeights()
{
var random = new Random();
diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
index 2b0c30f311..c44024d952 100644
--- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
@@ -18,7 +18,7 @@ namespace ControlCatalog.ViewModels
private WindowState _windowState;
private WindowState[] _windowStates;
private int _transparencyLevel;
- private ExtendClientAreaChromeHints _chromeHints;
+ private ExtendClientAreaChromeHints _chromeHints = ExtendClientAreaChromeHints.PreferSystemChrome;
private bool _extendClientAreaEnabled;
private bool _systemTitleBarEnabled;
private bool _preferSystemChromeEnabled;
diff --git a/samples/IntegrationTestApp/IntegrationTestApp.csproj b/samples/IntegrationTestApp/IntegrationTestApp.csproj
index e8338adae6..4284399357 100644
--- a/samples/IntegrationTestApp/IntegrationTestApp.csproj
+++ b/samples/IntegrationTestApp/IntegrationTestApp.csproj
@@ -1,4 +1,4 @@
-
+
WinExe
net6.0
@@ -18,6 +18,7 @@
+
diff --git a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj
index 9660d2a90d..4f7f06b529 100644
--- a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj
+++ b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj
@@ -7,6 +7,7 @@
+
diff --git a/samples/Previewer/Previewer.csproj b/samples/Previewer/Previewer.csproj
index c1d14cba26..98560e9ab0 100644
--- a/samples/Previewer/Previewer.csproj
+++ b/samples/Previewer/Previewer.csproj
@@ -9,6 +9,9 @@
+
+
+
diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml
index 429c4776d5..e6e62f86ed 100644
--- a/samples/RenderDemo/MainWindow.xaml
+++ b/samples/RenderDemo/MainWindow.xaml
@@ -72,5 +72,8 @@
+
+
+
diff --git a/samples/RenderDemo/Pages/PathMeasurementPage.cs b/samples/RenderDemo/Pages/PathMeasurementPage.cs
index 212377deae..cc5125609c 100644
--- a/samples/RenderDemo/Pages/PathMeasurementPage.cs
+++ b/samples/RenderDemo/Pages/PathMeasurementPage.cs
@@ -1,15 +1,9 @@
-using System;
-using System.Diagnostics;
-using System.Drawing.Drawing2D;
-using System.Security.Cryptography;
using Avalonia;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Media.Immutable;
-using Avalonia.Threading;
-using Avalonia.Visuals.Media.Imaging;
namespace RenderDemo.Pages
{
diff --git a/samples/RenderDemo/Pages/RenderTargetBitmapPage.cs b/samples/RenderDemo/Pages/RenderTargetBitmapPage.cs
index f263786ab7..f365b59c20 100644
--- a/samples/RenderDemo/Pages/RenderTargetBitmapPage.cs
+++ b/samples/RenderDemo/Pages/RenderTargetBitmapPage.cs
@@ -5,7 +5,6 @@ using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
-using Avalonia.Visuals.Media.Imaging;
namespace RenderDemo.Pages
{
diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml
new file mode 100644
index 0000000000..30ed35bbac
--- /dev/null
+++ b/samples/RenderDemo/Pages/Transform3DPage.axaml
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+ I'm a text
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml.cs b/samples/RenderDemo/Pages/Transform3DPage.axaml.cs
new file mode 100644
index 0000000000..5083189c4c
--- /dev/null
+++ b/samples/RenderDemo/Pages/Transform3DPage.axaml.cs
@@ -0,0 +1,21 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using RenderDemo.ViewModels;
+
+namespace RenderDemo.Pages;
+
+public class Transform3DPage : UserControl
+{
+ public Transform3DPage()
+ {
+ InitializeComponent();
+ this.DataContext = new Transform3DPageViewModel();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
+
diff --git a/samples/RenderDemo/RenderDemo.csproj b/samples/RenderDemo/RenderDemo.csproj
index 3d5aee49e9..3c62af1eaf 100644
--- a/samples/RenderDemo/RenderDemo.csproj
+++ b/samples/RenderDemo/RenderDemo.csproj
@@ -4,7 +4,7 @@
net6.0
-
+
TextFormatterPage.axaml
Code
@@ -12,6 +12,7 @@
+
diff --git a/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs
new file mode 100644
index 0000000000..c8d1d40e3a
--- /dev/null
+++ b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs
@@ -0,0 +1,55 @@
+using System;
+using MiniMvvm;
+using Avalonia.Animation;
+
+namespace RenderDemo.ViewModels
+{
+ public class Transform3DPageViewModel : ViewModelBase
+ {
+ private double _depth = 200;
+
+ private double _centerX = 0;
+ private double _centerY = 0;
+ private double _centerZ = 0;
+ private double _angleX = 0;
+ private double _angleY = 0;
+ private double _angleZ = 0;
+
+ public double Depth
+ {
+ get => _depth;
+ set => RaiseAndSetIfChanged(ref _depth, value);
+ }
+
+ public double CenterX
+ {
+ get => _centerX;
+ set => RaiseAndSetIfChanged(ref _centerX, value);
+ }
+ public double CenterY
+ {
+ get => _centerY;
+ set => RaiseAndSetIfChanged(ref _centerY, value);
+ }
+ public double CenterZ
+ {
+ get => _centerZ;
+ set => RaiseAndSetIfChanged(ref _centerZ, value);
+ }
+ public double AngleX
+ {
+ get => _angleX;
+ set => RaiseAndSetIfChanged(ref _angleX, value);
+ }
+ public double AngleY
+ {
+ get => _angleY;
+ set => RaiseAndSetIfChanged(ref _angleY, value);
+ }
+ public double AngleZ
+ {
+ get => _angleZ;
+ set => RaiseAndSetIfChanged(ref _angleZ, value);
+ }
+ }
+}
diff --git a/samples/SampleControls/HamburgerMenu/HamburgerMenu.cs b/samples/SampleControls/HamburgerMenu/HamburgerMenu.cs
index bbfd3d87ca..ab61dcde91 100644
--- a/samples/SampleControls/HamburgerMenu/HamburgerMenu.cs
+++ b/samples/SampleControls/HamburgerMenu/HamburgerMenu.cs
@@ -43,14 +43,13 @@ namespace ControlSamples
_splitView = e.NameScope.Find("PART_NavigationPane");
}
- protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == BoundsProperty && _splitView is not null)
{
- var oldBounds = change.OldValue.GetValueOrDefault();
- var newBounds = change.NewValue.GetValueOrDefault();
+ var (oldBounds, newBounds) = change.GetOldAndNewValue();
EnsureSplitViewMode(oldBounds, newBounds);
}
}
diff --git a/samples/Sandbox/Sandbox.csproj b/samples/Sandbox/Sandbox.csproj
index 8f2812e048..eab654acb6 100644
--- a/samples/Sandbox/Sandbox.csproj
+++ b/samples/Sandbox/Sandbox.csproj
@@ -8,7 +8,9 @@
+
+
diff --git a/samples/VirtualizationDemo/VirtualizationDemo.csproj b/samples/VirtualizationDemo/VirtualizationDemo.csproj
index 2c6ff74e5e..bd6054327f 100644
--- a/samples/VirtualizationDemo/VirtualizationDemo.csproj
+++ b/samples/VirtualizationDemo/VirtualizationDemo.csproj
@@ -5,6 +5,7 @@
+
diff --git a/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj b/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj
index cd9963a2e5..81b94b4d09 100644
--- a/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj
+++ b/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj
@@ -22,6 +22,7 @@
+
diff --git a/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj b/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj
index c25442b52c..2f3ea85e46 100644
--- a/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj
+++ b/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj
@@ -9,6 +9,7 @@
+
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index 8a475676a5..65a9adc937 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -40,7 +40,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_gl = GlPlatformSurface.TryCreate(this);
_framebuffer = new FramebufferManager(this);
- RenderScaling = (int)_view.Scaling;
+ RenderScaling = _view.Scaling;
MaxClientSize = new PixelSize(_view.Resources.DisplayMetrics.WidthPixels,
_view.Resources.DisplayMetrics.HeightPixels).ToSize(RenderScaling);
diff --git a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
deleted file mode 100644
index db0bb01410..0000000000
--- a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
- net6.0-android
- 21
- Exe
- enable
- com.Avalonia.AndroidTestApplication
- 1
- 1.0
- apk
- true
- portable
-
-
-
-
- Resources\drawable\Icon.png
-
-
-
-
- True
- True
- True
- True
-
-
-
-
-
-
- True
-
-
-
- True
-
-
-
-
-
-
-
diff --git a/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs b/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs
deleted file mode 100644
index 8f4beb2737..0000000000
--- a/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-using System;
-using Android.App;
-using Android.Content.PM;
-using Avalonia.Android;
-using Avalonia.Controls;
-using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Input.TextInput;
-using Avalonia.Markup.Xaml;
-using Avalonia.Media;
-using Avalonia.Styling;
-using Avalonia.Themes.Default;
-
-namespace Avalonia.AndroidTestApplication
-{
- [Activity(Label = "Main",
- MainLauncher = true,
- Icon = "@drawable/icon",
- Theme = "@style/Theme.AppCompat.NoActionBar",
- ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize,
- LaunchMode = LaunchMode.SingleInstance/*,
- ScreenOrientation = ScreenOrientation.Landscape*/)]
- public class MainActivity : AvaloniaActivity
- {
- protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
- {
- return base.CustomizeAppBuilder(builder);
- }
- }
-
- public class App : Application
- {
- public override void Initialize()
- {
- Styles.Add(new SimpleTheme(new Uri("avares://Avalonia.AndroidTestApplication")));
- }
-
- public override void OnFrameworkInitializationCompleted()
- {
- if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime)
- {
- singleViewLifetime.MainView = CreateSimpleWindow();
- }
-
- base.OnFrameworkInitializationCompleted();
- }
-
- // This provides a simple UI tree for testing input handling, drawing, etc
- public static ContentControl CreateSimpleWindow()
- {
- ContentControl window = new ContentControl()
- {
- Background = Brushes.Red,
- Content = new StackPanel
- {
- Margin = new Thickness(30),
- Background = Brushes.Yellow,
- Children =
- {
- new TextBlock
- {
- Text = "TEXT BLOCK",
- Width = 300,
- Height = 40,
- Background = Brushes.White,
- Foreground = Brushes.Black
- },
-
- new Button
- {
- Content = "BUTTON",
- Width = 150,
- Height = 40,
- Background = Brushes.LightGreen,
- Foreground = Brushes.Black
- },
-
- CreateTextBox(TextInputContentType.Normal),
- CreateTextBox(TextInputContentType.Password),
- CreateTextBox(TextInputContentType.Email),
- CreateTextBox(TextInputContentType.Url),
- CreateTextBox(TextInputContentType.Digits),
- CreateTextBox(TextInputContentType.Number),
- }
- }
- };
-
- return window;
- }
-
- private static TextBox CreateTextBox(TextInputContentType contentType)
- {
- var textBox = new TextBox()
- {
- Margin = new Thickness(20, 10),
- Watermark = contentType.ToString(),
- BorderThickness = new Thickness(3),
- FontSize = 20,
- [TextInputOptions.ContentTypeProperty] = contentType
- };
-
- return textBox;
- }
- }
-}
diff --git a/src/Android/Avalonia.AndroidTestApplication/Properties/AndroidManifest.xml b/src/Android/Avalonia.AndroidTestApplication/Properties/AndroidManifest.xml
deleted file mode 100644
index ad8134f628..0000000000
--- a/src/Android/Avalonia.AndroidTestApplication/Properties/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/src/Android/Avalonia.AndroidTestApplication/Resources/AboutResources.txt b/src/Android/Avalonia.AndroidTestApplication/Resources/AboutResources.txt
deleted file mode 100644
index 194ae28a59..0000000000
--- a/src/Android/Avalonia.AndroidTestApplication/Resources/AboutResources.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-Images, layout descriptions, binary blobs and string dictionaries can be included
-in your application as resource files. Various Android APIs are designed to
-operate on the resource IDs instead of dealing with images, strings or binary blobs
-directly.
-
-For example, a sample Android app that contains a user interface layout (main.xml),
-an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
-would keep its resources in the "Resources" directory of the application:
-
-Resources/
- drawable-hdpi/
- icon.png
-
- drawable-ldpi/
- icon.png
-
- drawable-mdpi/
- icon.png
-
- layout/
- main.xml
-
- values/
- strings.xml
-
-In order to get the build system to recognize Android resources, set the build action to
-"AndroidResource". The native Android APIs do not operate directly with filenames, but
-instead operate on resource IDs. When you compile an Android application that uses resources,
-the build system will package the resources for distribution and generate a class called
-"Resource" that contains the tokens for each one of the resources included. For example,
-for the above Resources layout, this is what the Resource class would expose:
-
-public class Resource {
- public class drawable {
- public const int icon = 0x123;
- }
-
- public class layout {
- public const int main = 0x456;
- }
-
- public class strings {
- public const int first_string = 0xabc;
- public const int second_string = 0xbcd;
- }
-}
-
-You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
-to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
-string in the dictionary file values/strings.xml.
\ No newline at end of file
diff --git a/src/Android/Avalonia.AndroidTestApplication/Resources/drawable/Icon.png b/src/Android/Avalonia.AndroidTestApplication/Resources/drawable/Icon.png
deleted file mode 100644
index 8074c4c571..0000000000
Binary files a/src/Android/Avalonia.AndroidTestApplication/Resources/drawable/Icon.png and /dev/null differ
diff --git a/src/Android/Avalonia.AndroidTestApplication/Resources/values/Strings.xml b/src/Android/Avalonia.AndroidTestApplication/Resources/values/Strings.xml
deleted file mode 100644
index c8dca13c35..0000000000
--- a/src/Android/Avalonia.AndroidTestApplication/Resources/values/Strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- Hello World, Click Me!
- Avalonia.AndroidTestApplication
-
\ No newline at end of file
diff --git a/src/Avalonia.Animation/Animatable.cs b/src/Avalonia.Animation/Animatable.cs
deleted file mode 100644
index 50fc5ac73b..0000000000
--- a/src/Avalonia.Animation/Animatable.cs
+++ /dev/null
@@ -1,253 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Linq;
-using Avalonia.Data;
-
-#nullable enable
-
-namespace Avalonia.Animation
-{
- ///
- /// Base class for all animatable objects.
- ///
- public class Animatable : AvaloniaObject
- {
- ///
- /// Defines the property.
- ///
- public static readonly StyledProperty ClockProperty =
- AvaloniaProperty.Register(nameof(Clock), inherits: true);
-
- ///
- /// Defines the property.
- ///
- public static readonly StyledProperty TransitionsProperty =
- AvaloniaProperty.Register(nameof(Transitions));
-
- private bool _transitionsEnabled = true;
- private Dictionary? _transitionState;
-
- ///
- /// Gets or sets the clock which controls the animations on the control.
- ///
- public IClock Clock
- {
- get => GetValue(ClockProperty);
- set => SetValue(ClockProperty, value);
- }
-
- ///
- /// Gets or sets the property transitions for the control.
- ///
- public Transitions? Transitions
- {
- get => GetValue(TransitionsProperty);
- set => SetValue(TransitionsProperty, value);
- }
-
- ///
- /// Enables transitions for the control.
- ///
- ///
- /// This method should not be called from user code, it will be called automatically by the framework
- /// when a control is added to the visual tree.
- ///
- protected void EnableTransitions()
- {
- if (!_transitionsEnabled)
- {
- _transitionsEnabled = true;
-
- if (Transitions is object)
- {
- AddTransitions(Transitions);
- }
- }
- }
-
- ///
- /// Disables transitions for the control.
- ///
- ///
- /// This method should not be called from user code, it will be called automatically by the framework
- /// when a control is added to the visual tree.
- ///
- protected void DisableTransitions()
- {
- if (_transitionsEnabled)
- {
- _transitionsEnabled = false;
-
- if (Transitions is object)
- {
- RemoveTransitions(Transitions);
- }
- }
- }
-
- protected sealed override void OnPropertyChangedCore(AvaloniaPropertyChangedEventArgs change)
- {
- if (change.Property == TransitionsProperty && change.IsEffectiveValueChange)
- {
- var oldTransitions = change.OldValue.GetValueOrDefault();
- var newTransitions = change.NewValue.GetValueOrDefault();
-
- // When transitions are replaced, we add the new transitions before removing the old
- // transitions, so that when the old transition being disposed causes the value to
- // change, there is a corresponding entry in `_transitionStates`. This means that we
- // need to account for any transitions present in both the old and new transitions
- // collections.
- if (newTransitions is object)
- {
- var toAdd = (IList)newTransitions;
-
- if (newTransitions.Count > 0 && oldTransitions?.Count > 0)
- {
- toAdd = newTransitions.Except(oldTransitions).ToList();
- }
-
- newTransitions.CollectionChanged += TransitionsCollectionChanged;
- AddTransitions(toAdd);
- }
-
- if (oldTransitions is object)
- {
- var toRemove = (IList)oldTransitions;
-
- if (oldTransitions.Count > 0 && newTransitions?.Count > 0)
- {
- toRemove = oldTransitions.Except(newTransitions).ToList();
- }
-
- oldTransitions.CollectionChanged -= TransitionsCollectionChanged;
- RemoveTransitions(toRemove);
- }
- }
- else if (_transitionsEnabled &&
- Transitions is object &&
- _transitionState is object &&
- !change.Property.IsDirect &&
- change.Priority > BindingPriority.Animation)
- {
- for (var i = Transitions.Count -1; i >= 0; --i)
- {
- var transition = Transitions[i];
-
- if (transition.Property == change.Property &&
- _transitionState.TryGetValue(transition, out var state))
- {
- var oldValue = state.BaseValue;
- var newValue = GetAnimationBaseValue(transition.Property);
-
- if (!Equals(oldValue, newValue))
- {
- state.BaseValue = newValue;
-
- // We need to transition from the current animated value if present,
- // instead of the old base value.
- var animatedValue = GetValue(transition.Property);
-
- if (!Equals(newValue, animatedValue))
- {
- oldValue = animatedValue;
- }
-
- state.Instance?.Dispose();
- state.Instance = transition.Apply(
- this,
- Clock ?? AvaloniaLocator.Current.GetRequiredService(),
- oldValue,
- newValue);
- return;
- }
- }
- }
- }
-
- base.OnPropertyChangedCore(change);
- }
-
- private void TransitionsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
- {
- if (!_transitionsEnabled)
- {
- return;
- }
-
- switch (e.Action)
- {
- case NotifyCollectionChangedAction.Add:
- AddTransitions(e.NewItems!);
- break;
- case NotifyCollectionChangedAction.Remove:
- RemoveTransitions(e.OldItems!);
- break;
- case NotifyCollectionChangedAction.Replace:
- RemoveTransitions(e.OldItems!);
- AddTransitions(e.NewItems!);
- break;
- case NotifyCollectionChangedAction.Reset:
- throw new NotSupportedException("Transitions collection cannot be reset.");
- }
- }
-
- private void AddTransitions(IList items)
- {
- if (!_transitionsEnabled)
- {
- return;
- }
-
- _transitionState ??= new Dictionary();
-
- for (var i = 0; i < items.Count; ++i)
- {
- var t = (ITransition)items[i]!;
-
- _transitionState.Add(t, new TransitionState
- {
- BaseValue = GetAnimationBaseValue(t.Property),
- });
- }
- }
-
- private void RemoveTransitions(IList items)
- {
- if (_transitionState is null)
- {
- return;
- }
-
- for (var i = 0; i < items.Count; ++i)
- {
- var t = (ITransition)items[i]!;
-
- if (_transitionState.TryGetValue(t, out var state))
- {
- state.Instance?.Dispose();
- _transitionState.Remove(t);
- }
- }
- }
-
- private object? GetAnimationBaseValue(AvaloniaProperty property)
- {
- var value = this.GetBaseValue(property, BindingPriority.LocalValue);
-
- if (value == AvaloniaProperty.UnsetValue)
- {
- value = GetValue(property);
- }
-
- return value;
- }
-
- private class TransitionState
- {
- public IDisposable? Instance { get; set; }
- public object? BaseValue { get; set; }
- }
- }
-}
diff --git a/src/Avalonia.Animation/ApiCompatBaseline.txt b/src/Avalonia.Animation/ApiCompatBaseline.txt
deleted file mode 100644
index 973698f872..0000000000
--- a/src/Avalonia.Animation/ApiCompatBaseline.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Compat issues with assembly Avalonia.Animation:
-InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Tasks.Task Avalonia.Animation.IAnimation.RunAsync(Avalonia.Animation.Animatable, Avalonia.Animation.IClock)' is present in the contract but not in the implementation.
-MembersMustExist : Member 'public System.Threading.Tasks.Task Avalonia.Animation.IAnimation.RunAsync(Avalonia.Animation.Animatable, Avalonia.Animation.IClock)' does not exist in the implementation but it does exist in the contract.
-InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Tasks.Task Avalonia.Animation.IAnimation.RunAsync(Avalonia.Animation.Animatable, Avalonia.Animation.IClock, System.Threading.CancellationToken)' is present in the implementation but not in the contract.
-Total Issues: 3
diff --git a/src/Avalonia.Animation/Avalonia.Animation.csproj b/src/Avalonia.Animation/Avalonia.Animation.csproj
deleted file mode 100644
index 80726f2884..0000000000
--- a/src/Avalonia.Animation/Avalonia.Animation.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- net6.0;netstandard2.0
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Avalonia.Animation/Easing/Easing.cs b/src/Avalonia.Animation/Easing/Easing.cs
deleted file mode 100644
index c721772f3e..0000000000
--- a/src/Avalonia.Animation/Easing/Easing.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Globalization;
-using System.Linq;
-
-namespace Avalonia.Animation.Easings
-{
- ///
- /// Base class for all Easing classes.
- ///
- [TypeConverter(typeof(EasingTypeConverter))]
- public abstract class Easing : IEasing
- {
- ///
- public abstract double Ease(double progress);
-
- static Dictionary? _easingTypes;
-
- static readonly Type s_thisType = typeof(Easing);
-
- ///
- /// Parses a Easing type string.
- ///
- /// The Easing type string.
- /// Returns the instance of the parsed type.
- public static Easing Parse(string e)
- {
- if (e.Contains(','))
- {
- return new SplineEasing(KeySpline.Parse(e, CultureInfo.InvariantCulture));
- }
-
- if (_easingTypes == null)
- {
- _easingTypes = new Dictionary();
-
- // Fetch the built-in easings.
- var derivedTypes = typeof(Easing).Assembly.GetTypes()
- .Where(p => p.Namespace == s_thisType.Namespace)
- .Where(p => p.IsSubclassOf(s_thisType))
- .Select(p => p);
-
- foreach (var easingType in derivedTypes)
- _easingTypes.Add(easingType.Name, easingType);
- }
-
- if (_easingTypes.ContainsKey(e))
- {
- var type = _easingTypes[e];
- return (Easing)Activator.CreateInstance(type)!;
- }
- else
- {
- throw new FormatException($"Easing \"{e}\" was not found in {s_thisType.Namespace} namespace.");
- }
- }
- }
-}
diff --git a/src/Avalonia.Animation/IAnimation.cs b/src/Avalonia.Animation/IAnimation.cs
deleted file mode 100644
index 436a765d27..0000000000
--- a/src/Avalonia.Animation/IAnimation.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Avalonia.Animation
-{
- ///
- /// Interface for Animation objects
- ///
- public interface IAnimation
- {
- ///
- /// Apply the animation to the specified control and run it when produces true.
- ///
- IDisposable Apply(Animatable control, IClock? clock, IObservable match, Action? onComplete = null);
-
- ///
- /// Run the animation on the specified control.
- ///
- Task RunAsync(Animatable control, IClock clock, CancellationToken cancellationToken = default);
- }
-}
diff --git a/src/Avalonia.Animation/IAnimationSetter.cs b/src/Avalonia.Animation/IAnimationSetter.cs
deleted file mode 100644
index 6a1d3539e2..0000000000
--- a/src/Avalonia.Animation/IAnimationSetter.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Avalonia.Animation
-{
- public interface IAnimationSetter
- {
- AvaloniaProperty? Property { get; set; }
- object? Value { get; set; }
- }
-}
diff --git a/src/Avalonia.Animation/IAnimator.cs b/src/Avalonia.Animation/IAnimator.cs
deleted file mode 100644
index f64ac9f913..0000000000
--- a/src/Avalonia.Animation/IAnimator.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Avalonia.Animation
-{
- ///
- /// Interface for Animator objects
- ///
- public interface IAnimator : IList
- {
- ///
- /// The target property.
- ///
- AvaloniaProperty? Property {get; set;}
-
- ///
- /// Applies the current KeyFrame group to the specified control.
- ///
- IDisposable? Apply(Animation animation, Animatable control, IClock? clock, IObservable match, Action? onComplete);
- }
-}
diff --git a/src/Avalonia.Animation/IClock.cs b/src/Avalonia.Animation/IClock.cs
deleted file mode 100644
index ae44102077..0000000000
--- a/src/Avalonia.Animation/IClock.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Avalonia.Animation
-{
- public interface IClock : IObservable
- {
- PlayState PlayState { get; set; }
- }
-}
diff --git a/src/Avalonia.Animation/IGlobalClock.cs b/src/Avalonia.Animation/IGlobalClock.cs
deleted file mode 100644
index b0455e2c80..0000000000
--- a/src/Avalonia.Animation/IGlobalClock.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Avalonia.Animation
-{
- public interface IGlobalClock : IClock
- {
- }
-}
diff --git a/src/Avalonia.Animation/ITransition.cs b/src/Avalonia.Animation/ITransition.cs
deleted file mode 100644
index 241ca208d1..0000000000
--- a/src/Avalonia.Animation/ITransition.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-
-namespace Avalonia.Animation
-{
- ///
- /// Interface for Transition objects.
- ///
- public interface ITransition
- {
- ///
- /// Applies the transition to the specified .
- ///
- IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue);
-
- ///
- /// Gets the property to be animated.
- ///
- AvaloniaProperty Property { get; set; }
-
- }
-}
diff --git a/src/Avalonia.Animation/Properties/AssemblyInfo.cs b/src/Avalonia.Animation/Properties/AssemblyInfo.cs
deleted file mode 100644
index 6b539b075b..0000000000
--- a/src/Avalonia.Animation/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Avalonia.Metadata;
-using System.Runtime.CompilerServices;
-
-[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation")]
-[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Easings")]
-[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Animators")]
-
-[assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-[assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
diff --git a/src/Avalonia.Base/Animation/Animatable.cs b/src/Avalonia.Base/Animation/Animatable.cs
new file mode 100644
index 0000000000..b045a32cd1
--- /dev/null
+++ b/src/Avalonia.Base/Animation/Animatable.cs
@@ -0,0 +1,254 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+using Avalonia.Data;
+
+#nullable enable
+
+namespace Avalonia.Animation
+{
+ ///
+ /// Base class for all animatable objects.
+ ///
+ public class Animatable : AvaloniaObject
+ {
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty ClockProperty =
+ AvaloniaProperty.Register(nameof(Clock), inherits: true);
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty TransitionsProperty =
+ AvaloniaProperty.Register(nameof(Transitions));
+
+ private bool _transitionsEnabled = true;
+ private Dictionary? _transitionState;
+
+ ///
+ /// Gets or sets the clock which controls the animations on the control.
+ ///
+ public IClock Clock
+ {
+ get => GetValue(ClockProperty);
+ set => SetValue(ClockProperty, value);
+ }
+
+ ///
+ /// Gets or sets the property transitions for the control.
+ ///
+ public Transitions? Transitions
+ {
+ get => GetValue(TransitionsProperty);
+ set => SetValue(TransitionsProperty, value);
+ }
+
+ ///
+ /// Enables transitions for the control.
+ ///
+ ///
+ /// This method should not be called from user code, it will be called automatically by the framework
+ /// when a control is added to the visual tree.
+ ///
+ protected void EnableTransitions()
+ {
+ if (!_transitionsEnabled)
+ {
+ _transitionsEnabled = true;
+
+ if (Transitions is object)
+ {
+ AddTransitions(Transitions);
+ }
+ }
+ }
+
+ ///
+ /// Disables transitions for the control.
+ ///
+ ///
+ /// This method should not be called from user code, it will be called automatically by the framework
+ /// when a control is added to the visual tree.
+ ///
+ protected void DisableTransitions()
+ {
+ if (_transitionsEnabled)
+ {
+ _transitionsEnabled = false;
+
+ if (Transitions is object)
+ {
+ RemoveTransitions(Transitions);
+ }
+ }
+ }
+
+ protected sealed override void OnPropertyChangedCore(AvaloniaPropertyChangedEventArgs change)
+ {
+ if (change.Property == TransitionsProperty && change.IsEffectiveValueChange)
+ {
+ var e = (AvaloniaPropertyChangedEventArgs)change;
+ var oldTransitions = e.OldValue.GetValueOrDefault();
+ var newTransitions = e.NewValue.GetValueOrDefault();
+
+ // When transitions are replaced, we add the new transitions before removing the old
+ // transitions, so that when the old transition being disposed causes the value to
+ // change, there is a corresponding entry in `_transitionStates`. This means that we
+ // need to account for any transitions present in both the old and new transitions
+ // collections.
+ if (newTransitions is object)
+ {
+ var toAdd = (IList)newTransitions;
+
+ if (newTransitions.Count > 0 && oldTransitions?.Count > 0)
+ {
+ toAdd = newTransitions.Except(oldTransitions).ToList();
+ }
+
+ newTransitions.CollectionChanged += TransitionsCollectionChanged;
+ AddTransitions(toAdd);
+ }
+
+ if (oldTransitions is object)
+ {
+ var toRemove = (IList)oldTransitions;
+
+ if (oldTransitions.Count > 0 && newTransitions?.Count > 0)
+ {
+ toRemove = oldTransitions.Except(newTransitions).ToList();
+ }
+
+ oldTransitions.CollectionChanged -= TransitionsCollectionChanged;
+ RemoveTransitions(toRemove);
+ }
+ }
+ else if (_transitionsEnabled &&
+ Transitions is object &&
+ _transitionState is object &&
+ !change.Property.IsDirect &&
+ change.Priority > BindingPriority.Animation)
+ {
+ for (var i = Transitions.Count -1; i >= 0; --i)
+ {
+ var transition = Transitions[i];
+
+ if (transition.Property == change.Property &&
+ _transitionState.TryGetValue(transition, out var state))
+ {
+ var oldValue = state.BaseValue;
+ var newValue = GetAnimationBaseValue(transition.Property);
+
+ if (!Equals(oldValue, newValue))
+ {
+ state.BaseValue = newValue;
+
+ // We need to transition from the current animated value if present,
+ // instead of the old base value.
+ var animatedValue = GetValue(transition.Property);
+
+ if (!Equals(newValue, animatedValue))
+ {
+ oldValue = animatedValue;
+ }
+
+ state.Instance?.Dispose();
+ state.Instance = transition.Apply(
+ this,
+ Clock ?? AvaloniaLocator.Current.GetRequiredService(),
+ oldValue,
+ newValue);
+ return;
+ }
+ }
+ }
+ }
+
+ base.OnPropertyChangedCore(change);
+ }
+
+ private void TransitionsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
+ {
+ if (!_transitionsEnabled)
+ {
+ return;
+ }
+
+ switch (e.Action)
+ {
+ case NotifyCollectionChangedAction.Add:
+ AddTransitions(e.NewItems!);
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ RemoveTransitions(e.OldItems!);
+ break;
+ case NotifyCollectionChangedAction.Replace:
+ RemoveTransitions(e.OldItems!);
+ AddTransitions(e.NewItems!);
+ break;
+ case NotifyCollectionChangedAction.Reset:
+ throw new NotSupportedException("Transitions collection cannot be reset.");
+ }
+ }
+
+ private void AddTransitions(IList items)
+ {
+ if (!_transitionsEnabled)
+ {
+ return;
+ }
+
+ _transitionState ??= new Dictionary();
+
+ for (var i = 0; i < items.Count; ++i)
+ {
+ var t = (ITransition)items[i]!;
+
+ _transitionState.Add(t, new TransitionState
+ {
+ BaseValue = GetAnimationBaseValue(t.Property),
+ });
+ }
+ }
+
+ private void RemoveTransitions(IList items)
+ {
+ if (_transitionState is null)
+ {
+ return;
+ }
+
+ for (var i = 0; i < items.Count; ++i)
+ {
+ var t = (ITransition)items[i]!;
+
+ if (_transitionState.TryGetValue(t, out var state))
+ {
+ state.Instance?.Dispose();
+ _transitionState.Remove(t);
+ }
+ }
+ }
+
+ private object? GetAnimationBaseValue(AvaloniaProperty property)
+ {
+ var value = this.GetBaseValue(property, BindingPriority.LocalValue);
+
+ if (value == AvaloniaProperty.UnsetValue)
+ {
+ value = GetValue(property);
+ }
+
+ return value;
+ }
+
+ private class TransitionState
+ {
+ public IDisposable? Instance { get; set; }
+ public object? BaseValue { get; set; }
+ }
+ }
+}
diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Base/Animation/Animation.cs
similarity index 100%
rename from src/Avalonia.Animation/Animation.cs
rename to src/Avalonia.Base/Animation/Animation.cs
diff --git a/src/Avalonia.Animation/AnimationInstance`1.cs b/src/Avalonia.Base/Animation/AnimationInstance`1.cs
similarity index 100%
rename from src/Avalonia.Animation/AnimationInstance`1.cs
rename to src/Avalonia.Base/Animation/AnimationInstance`1.cs
diff --git a/src/Avalonia.Animation/AnimatorDrivenTransition.cs b/src/Avalonia.Base/Animation/AnimatorDrivenTransition.cs
similarity index 100%
rename from src/Avalonia.Animation/AnimatorDrivenTransition.cs
rename to src/Avalonia.Base/Animation/AnimatorDrivenTransition.cs
diff --git a/src/Avalonia.Animation/AnimatorKeyFrame.cs b/src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
similarity index 100%
rename from src/Avalonia.Animation/AnimatorKeyFrame.cs
rename to src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
diff --git a/src/Avalonia.Animation/AnimatorTransitionObservable.cs b/src/Avalonia.Base/Animation/AnimatorTransitionObservable.cs
similarity index 100%
rename from src/Avalonia.Animation/AnimatorTransitionObservable.cs
rename to src/Avalonia.Base/Animation/AnimatorTransitionObservable.cs
diff --git a/src/Avalonia.Animation/Animators/Animator`1.cs b/src/Avalonia.Base/Animation/Animators/Animator`1.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/Animator`1.cs
rename to src/Avalonia.Base/Animation/Animators/Animator`1.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/BaseBrushAnimator.cs b/src/Avalonia.Base/Animation/Animators/BaseBrushAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/BaseBrushAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/BaseBrushAnimator.cs
diff --git a/src/Avalonia.Animation/Animators/BoolAnimator.cs b/src/Avalonia.Base/Animation/Animators/BoolAnimator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/BoolAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/BoolAnimator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/BoxShadowAnimator.cs b/src/Avalonia.Base/Animation/Animators/BoxShadowAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/BoxShadowAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/BoxShadowAnimator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/BoxShadowsAnimator.cs b/src/Avalonia.Base/Animation/Animators/BoxShadowsAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/BoxShadowsAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/BoxShadowsAnimator.cs
diff --git a/src/Avalonia.Animation/Animators/ByteAnimator.cs b/src/Avalonia.Base/Animation/Animators/ByteAnimator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/ByteAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/ByteAnimator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/ColorAnimator.cs b/src/Avalonia.Base/Animation/Animators/ColorAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/ColorAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/ColorAnimator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/CornerRadiusAnimator.cs b/src/Avalonia.Base/Animation/Animators/CornerRadiusAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/CornerRadiusAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/CornerRadiusAnimator.cs
diff --git a/src/Avalonia.Animation/Animators/DecimalAnimator.cs b/src/Avalonia.Base/Animation/Animators/DecimalAnimator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/DecimalAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/DecimalAnimator.cs
diff --git a/src/Avalonia.Animation/Animators/DoubleAnimator.cs b/src/Avalonia.Base/Animation/Animators/DoubleAnimator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/DoubleAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/DoubleAnimator.cs
diff --git a/src/Avalonia.Animation/Animators/FloatAnimator.cs b/src/Avalonia.Base/Animation/Animators/FloatAnimator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/FloatAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/FloatAnimator.cs
diff --git a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
new file mode 100644
index 0000000000..4727ea1bfb
--- /dev/null
+++ b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Collections.Generic;
+
+using Avalonia.Data;
+using Avalonia.Media;
+using Avalonia.Media.Immutable;
+
+#nullable enable
+
+namespace Avalonia.Animation.Animators
+{
+ ///
+ /// Animator that handles values.
+ ///
+ public class GradientBrushAnimator : Animator
+ {
+ private static readonly RelativePointAnimator s_relativePointAnimator = new RelativePointAnimator();
+ private static readonly DoubleAnimator s_doubleAnimator = new DoubleAnimator();
+
+ public override IGradientBrush? Interpolate(double progress, IGradientBrush? oldValue, IGradientBrush? newValue)
+ {
+ if (oldValue is null || newValue is null)
+ {
+ return progress >= 0.5 ? newValue : oldValue;
+ }
+
+ switch (oldValue)
+ {
+ case IRadialGradientBrush oldRadial when newValue is IRadialGradientBrush newRadial:
+ return new ImmutableRadialGradientBrush(
+ InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops),
+ s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity),
+ oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null,
+ s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin),
+ oldValue.SpreadMethod,
+ s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center),
+ s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin),
+ s_doubleAnimator.Interpolate(progress, oldRadial.Radius, newRadial.Radius));
+
+ case IConicGradientBrush oldConic when newValue is IConicGradientBrush newConic:
+ return new ImmutableConicGradientBrush(
+ InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops),
+ s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity),
+ oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null,
+ s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin),
+ oldValue.SpreadMethod,
+ s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center),
+ s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle));
+
+ case ILinearGradientBrush oldLinear when newValue is ILinearGradientBrush newLinear:
+ return new ImmutableLinearGradientBrush(
+ InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops),
+ s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity),
+ oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null,
+ s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin),
+ oldValue.SpreadMethod,
+ s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint),
+ s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint));
+
+ default:
+ return progress >= 0.5 ? newValue : oldValue;
+ }
+ }
+
+ public override IDisposable BindAnimation(Animatable control, IObservable instance)
+ {
+ if (Property is null)
+ {
+ throw new InvalidOperationException("Animator has no property specified.");
+ }
+
+ return control.Bind((AvaloniaProperty)Property, instance, BindingPriority.Animation);
+ }
+
+ private IReadOnlyList InterpolateStops(double progress, IReadOnlyList oldValue, IReadOnlyList newValue)
+ {
+ var resultCount = Math.Max(oldValue.Count, newValue.Count);
+ var stops = new ImmutableGradientStop[resultCount];
+
+ for (int index = 0, oldIndex = 0, newIndex = 0; index < resultCount; index++)
+ {
+ stops[index] = new ImmutableGradientStop(
+ s_doubleAnimator.Interpolate(progress, oldValue[oldIndex].Offset, newValue[newIndex].Offset),
+ ColorAnimator.InterpolateCore(progress, oldValue[oldIndex].Color, newValue[newIndex].Color));
+
+ if (oldIndex < oldValue.Count - 1)
+ {
+ oldIndex++;
+ }
+
+ if (newIndex < newValue.Count - 1)
+ {
+ newIndex++;
+ }
+ }
+
+ return stops;
+ }
+
+ internal static IGradientBrush ConvertSolidColorBrushToGradient(IGradientBrush gradientBrush, ISolidColorBrush solidColorBrush)
+ {
+ switch (gradientBrush)
+ {
+ case IRadialGradientBrush oldRadial:
+ return new ImmutableRadialGradientBrush(
+ CreateStopsFromSolidColorBrush(solidColorBrush, oldRadial.GradientStops), solidColorBrush.Opacity,
+ oldRadial.Transform is { } ? new ImmutableTransform(oldRadial.Transform.Value) : null,
+ oldRadial.TransformOrigin,
+ oldRadial.SpreadMethod, oldRadial.Center, oldRadial.GradientOrigin, oldRadial.Radius);
+
+ case IConicGradientBrush oldConic:
+ return new ImmutableConicGradientBrush(
+ CreateStopsFromSolidColorBrush(solidColorBrush, oldConic.GradientStops), solidColorBrush.Opacity,
+ oldConic.Transform is { } ? new ImmutableTransform(oldConic.Transform.Value) : null,
+ oldConic.TransformOrigin,
+ oldConic.SpreadMethod, oldConic.Center, oldConic.Angle);
+
+ case ILinearGradientBrush oldLinear:
+ return new ImmutableLinearGradientBrush(
+ CreateStopsFromSolidColorBrush(solidColorBrush, oldLinear.GradientStops), solidColorBrush.Opacity,
+ oldLinear.Transform is { } ? new ImmutableTransform(oldLinear.Transform.Value) : null,
+ oldLinear.TransformOrigin,
+ oldLinear.SpreadMethod, oldLinear.StartPoint, oldLinear.EndPoint);
+
+ default:
+ throw new NotSupportedException($"Gradient of type {gradientBrush?.GetType()} is not supported");
+ }
+
+ static IReadOnlyList CreateStopsFromSolidColorBrush(ISolidColorBrush solidColorBrush, IReadOnlyList baseStops)
+ {
+ var stops = new ImmutableGradientStop[baseStops.Count];
+ for (int index = 0; index < baseStops.Count; index++)
+ {
+ stops[index] = new ImmutableGradientStop(baseStops[index].Offset, solidColorBrush.Color);
+ }
+ return stops;
+ }
+ }
+ }
+}
diff --git a/src/Avalonia.Animation/Animators/Int16Animator.cs b/src/Avalonia.Base/Animation/Animators/Int16Animator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/Int16Animator.cs
rename to src/Avalonia.Base/Animation/Animators/Int16Animator.cs
diff --git a/src/Avalonia.Animation/Animators/Int32Animator.cs b/src/Avalonia.Base/Animation/Animators/Int32Animator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/Int32Animator.cs
rename to src/Avalonia.Base/Animation/Animators/Int32Animator.cs
diff --git a/src/Avalonia.Animation/Animators/Int64Animator.cs b/src/Avalonia.Base/Animation/Animators/Int64Animator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/Int64Animator.cs
rename to src/Avalonia.Base/Animation/Animators/Int64Animator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/PointAnimator.cs b/src/Avalonia.Base/Animation/Animators/PointAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/PointAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/PointAnimator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/RectAnimator.cs b/src/Avalonia.Base/Animation/Animators/RectAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/RectAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/RectAnimator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/RelativePointAnimator.cs b/src/Avalonia.Base/Animation/Animators/RelativePointAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/RelativePointAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/RelativePointAnimator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/SizeAnimator.cs b/src/Avalonia.Base/Animation/Animators/SizeAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/SizeAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/SizeAnimator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/SolidColorBrushAnimator.cs b/src/Avalonia.Base/Animation/Animators/SolidColorBrushAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/SolidColorBrushAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/SolidColorBrushAnimator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/ThicknessAnimator.cs b/src/Avalonia.Base/Animation/Animators/ThicknessAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/ThicknessAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/ThicknessAnimator.cs
diff --git a/src/Avalonia.Base/Animation/Animators/TransformAnimator.cs b/src/Avalonia.Base/Animation/Animators/TransformAnimator.cs
new file mode 100644
index 0000000000..e12ca722f9
--- /dev/null
+++ b/src/Avalonia.Base/Animation/Animators/TransformAnimator.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Reactive.Disposables;
+using Avalonia.Logging;
+using Avalonia.Media;
+using Avalonia.Media.Transformation;
+
+namespace Avalonia.Animation.Animators
+{
+ ///
+ /// Animator that handles properties.
+ ///
+ public class TransformAnimator : Animator
+ {
+ DoubleAnimator? _doubleAnimator;
+
+ ///
+ public override IDisposable? Apply(Animation animation, Animatable control, IClock? clock, IObservable obsMatch, Action? onComplete)
+ {
+ var ctrl = (Visual)control;
+
+ if (Property is null)
+ {
+ throw new InvalidOperationException("Animator has no property specified.");
+ }
+
+ // Check if the Target Property is Transform derived.
+ if (typeof(Transform).IsAssignableFrom(Property.OwnerType))
+ {
+ if (ctrl.RenderTransform is TransformOperations)
+ {
+ // HACK: This animator cannot reasonably animate CSS transforms at the moment.
+ return Disposable.Empty;
+ }
+
+ if (ctrl.RenderTransform == null)
+ {
+ var normalTransform = new TransformGroup();
+
+ // Add the transforms according to MS Expression Blend's
+ // default RenderTransform order.
+
+ normalTransform.Children.Add(new ScaleTransform());
+ normalTransform.Children.Add(new SkewTransform());
+ normalTransform.Children.Add(new RotateTransform());
+ normalTransform.Children.Add(new TranslateTransform());
+ normalTransform.Children.Add(new Rotate3DTransform());
+
+ ctrl.RenderTransform = normalTransform;
+ }
+
+ var renderTransformType = ctrl.RenderTransform.GetType();
+
+ if (_doubleAnimator == null)
+ {
+ _doubleAnimator = new DoubleAnimator();
+
+ foreach (AnimatorKeyFrame keyframe in this)
+ {
+ _doubleAnimator.Add(keyframe);
+ }
+
+ _doubleAnimator.Property = Property;
+ }
+
+ // It's a transform object so let's target that.
+ if (renderTransformType == Property.OwnerType)
+ {
+ return _doubleAnimator.Apply(animation, (Transform) ctrl.RenderTransform, clock ?? control.Clock, obsMatch, onComplete);
+ }
+ // It's a TransformGroup and try finding the target there.
+ else if (renderTransformType == typeof(TransformGroup))
+ {
+ foreach (Transform transform in ((TransformGroup)ctrl.RenderTransform).Children)
+ {
+ if (transform.GetType() == Property.OwnerType)
+ {
+ return _doubleAnimator.Apply(animation, transform, clock ?? control.Clock, obsMatch, onComplete);
+ }
+ }
+ }
+
+ Logger.TryGet(LogEventLevel.Warning, LogArea.Animations)?.Log(
+ control,
+ $"Cannot find the appropriate transform: \"{Property.OwnerType}\" in {control}.");
+ }
+ else
+ {
+ Logger.TryGet(LogEventLevel.Error, LogArea.Animations)?.Log(
+ control,
+ $"Cannot apply animation: Target property owner {Property.OwnerType} is not a Transform object.");
+ }
+ return null;
+ }
+
+ ///
+ public override double Interpolate(double p, double o, double n) => 0;
+ }
+}
diff --git a/src/Avalonia.Visuals/Animation/Animators/TransformOperationsAnimator.cs b/src/Avalonia.Base/Animation/Animators/TransformOperationsAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/TransformOperationsAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/TransformOperationsAnimator.cs
diff --git a/src/Avalonia.Animation/Animators/UInt16Animator.cs b/src/Avalonia.Base/Animation/Animators/UInt16Animator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/UInt16Animator.cs
rename to src/Avalonia.Base/Animation/Animators/UInt16Animator.cs
diff --git a/src/Avalonia.Animation/Animators/UInt32Animator.cs b/src/Avalonia.Base/Animation/Animators/UInt32Animator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/UInt32Animator.cs
rename to src/Avalonia.Base/Animation/Animators/UInt32Animator.cs
diff --git a/src/Avalonia.Animation/Animators/UInt64Animator.cs b/src/Avalonia.Base/Animation/Animators/UInt64Animator.cs
similarity index 100%
rename from src/Avalonia.Animation/Animators/UInt64Animator.cs
rename to src/Avalonia.Base/Animation/Animators/UInt64Animator.cs
diff --git a/src/Avalonia.Visuals/Animation/Animators/VectorAnimator.cs b/src/Avalonia.Base/Animation/Animators/VectorAnimator.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Animators/VectorAnimator.cs
rename to src/Avalonia.Base/Animation/Animators/VectorAnimator.cs
diff --git a/src/Avalonia.Animation/Clock.cs b/src/Avalonia.Base/Animation/Clock.cs
similarity index 100%
rename from src/Avalonia.Animation/Clock.cs
rename to src/Avalonia.Base/Animation/Clock.cs
diff --git a/src/Avalonia.Animation/ClockBase.cs b/src/Avalonia.Base/Animation/ClockBase.cs
similarity index 100%
rename from src/Avalonia.Animation/ClockBase.cs
rename to src/Avalonia.Base/Animation/ClockBase.cs
diff --git a/src/Avalonia.Visuals/Animation/CompositePageTransition.cs b/src/Avalonia.Base/Animation/CompositePageTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/CompositePageTransition.cs
rename to src/Avalonia.Base/Animation/CompositePageTransition.cs
diff --git a/src/Avalonia.Visuals/Animation/CrossFade.cs b/src/Avalonia.Base/Animation/CrossFade.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/CrossFade.cs
rename to src/Avalonia.Base/Animation/CrossFade.cs
diff --git a/src/Avalonia.Animation/Cue.cs b/src/Avalonia.Base/Animation/Cue.cs
similarity index 100%
rename from src/Avalonia.Animation/Cue.cs
rename to src/Avalonia.Base/Animation/Cue.cs
diff --git a/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs b/src/Avalonia.Base/Animation/DisposeAnimationInstanceSubject.cs
similarity index 100%
rename from src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs
rename to src/Avalonia.Base/Animation/DisposeAnimationInstanceSubject.cs
diff --git a/src/Avalonia.Animation/Easing/BackEaseIn.cs b/src/Avalonia.Base/Animation/Easings/BackEaseIn.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/BackEaseIn.cs
rename to src/Avalonia.Base/Animation/Easings/BackEaseIn.cs
diff --git a/src/Avalonia.Animation/Easing/BackEaseInOut.cs b/src/Avalonia.Base/Animation/Easings/BackEaseInOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/BackEaseInOut.cs
rename to src/Avalonia.Base/Animation/Easings/BackEaseInOut.cs
diff --git a/src/Avalonia.Animation/Easing/BackEaseOut.cs b/src/Avalonia.Base/Animation/Easings/BackEaseOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/BackEaseOut.cs
rename to src/Avalonia.Base/Animation/Easings/BackEaseOut.cs
diff --git a/src/Avalonia.Animation/Easing/BounceEaseIn.cs b/src/Avalonia.Base/Animation/Easings/BounceEaseIn.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/BounceEaseIn.cs
rename to src/Avalonia.Base/Animation/Easings/BounceEaseIn.cs
diff --git a/src/Avalonia.Animation/Easing/BounceEaseInOut.cs b/src/Avalonia.Base/Animation/Easings/BounceEaseInOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/BounceEaseInOut.cs
rename to src/Avalonia.Base/Animation/Easings/BounceEaseInOut.cs
diff --git a/src/Avalonia.Animation/Easing/BounceEaseOut.cs b/src/Avalonia.Base/Animation/Easings/BounceEaseOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/BounceEaseOut.cs
rename to src/Avalonia.Base/Animation/Easings/BounceEaseOut.cs
diff --git a/src/Avalonia.Animation/Easing/CircularEaseIn.cs b/src/Avalonia.Base/Animation/Easings/CircularEaseIn.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/CircularEaseIn.cs
rename to src/Avalonia.Base/Animation/Easings/CircularEaseIn.cs
diff --git a/src/Avalonia.Animation/Easing/CircularEaseInOut.cs b/src/Avalonia.Base/Animation/Easings/CircularEaseInOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/CircularEaseInOut.cs
rename to src/Avalonia.Base/Animation/Easings/CircularEaseInOut.cs
diff --git a/src/Avalonia.Animation/Easing/CircularEaseOut.cs b/src/Avalonia.Base/Animation/Easings/CircularEaseOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/CircularEaseOut.cs
rename to src/Avalonia.Base/Animation/Easings/CircularEaseOut.cs
diff --git a/src/Avalonia.Animation/Easing/CubicEaseIn.cs b/src/Avalonia.Base/Animation/Easings/CubicEaseIn.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/CubicEaseIn.cs
rename to src/Avalonia.Base/Animation/Easings/CubicEaseIn.cs
diff --git a/src/Avalonia.Animation/Easing/CubicEaseInOut.cs b/src/Avalonia.Base/Animation/Easings/CubicEaseInOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/CubicEaseInOut.cs
rename to src/Avalonia.Base/Animation/Easings/CubicEaseInOut.cs
diff --git a/src/Avalonia.Animation/Easing/CubicEaseOut.cs b/src/Avalonia.Base/Animation/Easings/CubicEaseOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/CubicEaseOut.cs
rename to src/Avalonia.Base/Animation/Easings/CubicEaseOut.cs
diff --git a/src/Avalonia.Base/Animation/Easings/Easing.cs b/src/Avalonia.Base/Animation/Easings/Easing.cs
new file mode 100644
index 0000000000..d4f817ccc3
--- /dev/null
+++ b/src/Avalonia.Base/Animation/Easings/Easing.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using Avalonia.SourceGenerator;
+
+namespace Avalonia.Animation.Easings
+{
+ ///
+ /// Base class for all Easing classes.
+ ///
+ [TypeConverter(typeof(EasingTypeConverter))]
+ public abstract partial class Easing : IEasing
+ {
+ ///
+ public abstract double Ease(double progress);
+
+ private const string Namespace = "Avalonia.Animation.Easings";
+
+ [SubtypesFactory(typeof(Easing), Namespace)]
+ private static partial bool TryCreateEasingInstance(string type, [NotNullWhen(true)] out Easing? instance);
+
+ ///
+ /// Parses a Easing type string.
+ ///
+ /// The Easing type string.
+ /// Returns the instance of the parsed type.
+ public static Easing Parse(string e)
+ {
+#if NETSTANDARD2_0
+ if (e.Contains(","))
+#else
+ if (e.Contains(','))
+#endif
+ {
+ return new SplineEasing(KeySpline.Parse(e, CultureInfo.InvariantCulture));
+ }
+
+ return TryCreateEasingInstance(e, out var easing)
+ ? easing
+ : throw new FormatException($"Easing \"{e}\" was not found in {Namespace} namespace.");
+ }
+ }
+}
diff --git a/src/Avalonia.Animation/Easing/EasingTypeConverter.cs b/src/Avalonia.Base/Animation/Easings/EasingTypeConverter.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/EasingTypeConverter.cs
rename to src/Avalonia.Base/Animation/Easings/EasingTypeConverter.cs
diff --git a/src/Avalonia.Animation/Easing/ElasticEaseIn.cs b/src/Avalonia.Base/Animation/Easings/ElasticEaseIn.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/ElasticEaseIn.cs
rename to src/Avalonia.Base/Animation/Easings/ElasticEaseIn.cs
diff --git a/src/Avalonia.Animation/Easing/ElasticEaseInOut.cs b/src/Avalonia.Base/Animation/Easings/ElasticEaseInOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/ElasticEaseInOut.cs
rename to src/Avalonia.Base/Animation/Easings/ElasticEaseInOut.cs
diff --git a/src/Avalonia.Animation/Easing/ElasticEaseOut.cs b/src/Avalonia.Base/Animation/Easings/ElasticEaseOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/ElasticEaseOut.cs
rename to src/Avalonia.Base/Animation/Easings/ElasticEaseOut.cs
diff --git a/src/Avalonia.Animation/Easing/ExponentialEaseIn.cs b/src/Avalonia.Base/Animation/Easings/ExponentialEaseIn.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/ExponentialEaseIn.cs
rename to src/Avalonia.Base/Animation/Easings/ExponentialEaseIn.cs
diff --git a/src/Avalonia.Animation/Easing/ExponentialEaseInOut.cs b/src/Avalonia.Base/Animation/Easings/ExponentialEaseInOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/ExponentialEaseInOut.cs
rename to src/Avalonia.Base/Animation/Easings/ExponentialEaseInOut.cs
diff --git a/src/Avalonia.Animation/Easing/ExponentialEaseOut.cs b/src/Avalonia.Base/Animation/Easings/ExponentialEaseOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/ExponentialEaseOut.cs
rename to src/Avalonia.Base/Animation/Easings/ExponentialEaseOut.cs
diff --git a/src/Avalonia.Animation/Easing/IEasing.cs b/src/Avalonia.Base/Animation/Easings/IEasing.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/IEasing.cs
rename to src/Avalonia.Base/Animation/Easings/IEasing.cs
diff --git a/src/Avalonia.Animation/Easing/LinearEasing.cs b/src/Avalonia.Base/Animation/Easings/LinearEasing.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/LinearEasing.cs
rename to src/Avalonia.Base/Animation/Easings/LinearEasing.cs
diff --git a/src/Avalonia.Animation/Easing/QuadraticEaseIn.cs b/src/Avalonia.Base/Animation/Easings/QuadraticEaseIn.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/QuadraticEaseIn.cs
rename to src/Avalonia.Base/Animation/Easings/QuadraticEaseIn.cs
diff --git a/src/Avalonia.Animation/Easing/QuadraticEaseInOut.cs b/src/Avalonia.Base/Animation/Easings/QuadraticEaseInOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/QuadraticEaseInOut.cs
rename to src/Avalonia.Base/Animation/Easings/QuadraticEaseInOut.cs
diff --git a/src/Avalonia.Animation/Easing/QuadraticEaseOut.cs b/src/Avalonia.Base/Animation/Easings/QuadraticEaseOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/QuadraticEaseOut.cs
rename to src/Avalonia.Base/Animation/Easings/QuadraticEaseOut.cs
diff --git a/src/Avalonia.Animation/Easing/QuarticEaseIn.cs b/src/Avalonia.Base/Animation/Easings/QuarticEaseIn.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/QuarticEaseIn.cs
rename to src/Avalonia.Base/Animation/Easings/QuarticEaseIn.cs
diff --git a/src/Avalonia.Animation/Easing/QuarticEaseInOut.cs b/src/Avalonia.Base/Animation/Easings/QuarticEaseInOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/QuarticEaseInOut.cs
rename to src/Avalonia.Base/Animation/Easings/QuarticEaseInOut.cs
diff --git a/src/Avalonia.Animation/Easing/QuarticEaseOut.cs b/src/Avalonia.Base/Animation/Easings/QuarticEaseOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/QuarticEaseOut.cs
rename to src/Avalonia.Base/Animation/Easings/QuarticEaseOut.cs
diff --git a/src/Avalonia.Animation/Easing/QuinticEaseIn.cs b/src/Avalonia.Base/Animation/Easings/QuinticEaseIn.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/QuinticEaseIn.cs
rename to src/Avalonia.Base/Animation/Easings/QuinticEaseIn.cs
diff --git a/src/Avalonia.Animation/Easing/QuinticEaseInOut.cs b/src/Avalonia.Base/Animation/Easings/QuinticEaseInOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/QuinticEaseInOut.cs
rename to src/Avalonia.Base/Animation/Easings/QuinticEaseInOut.cs
diff --git a/src/Avalonia.Animation/Easing/QuinticEaseOut.cs b/src/Avalonia.Base/Animation/Easings/QuinticEaseOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/QuinticEaseOut.cs
rename to src/Avalonia.Base/Animation/Easings/QuinticEaseOut.cs
diff --git a/src/Avalonia.Animation/Easing/SineEaseIn.cs b/src/Avalonia.Base/Animation/Easings/SineEaseIn.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/SineEaseIn.cs
rename to src/Avalonia.Base/Animation/Easings/SineEaseIn.cs
diff --git a/src/Avalonia.Animation/Easing/SineEaseInOut.cs b/src/Avalonia.Base/Animation/Easings/SineEaseInOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/SineEaseInOut.cs
rename to src/Avalonia.Base/Animation/Easings/SineEaseInOut.cs
diff --git a/src/Avalonia.Animation/Easing/SineEaseOut.cs b/src/Avalonia.Base/Animation/Easings/SineEaseOut.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/SineEaseOut.cs
rename to src/Avalonia.Base/Animation/Easings/SineEaseOut.cs
diff --git a/src/Avalonia.Animation/Easing/SplineEasing.cs b/src/Avalonia.Base/Animation/Easings/SplineEasing.cs
similarity index 100%
rename from src/Avalonia.Animation/Easing/SplineEasing.cs
rename to src/Avalonia.Base/Animation/Easings/SplineEasing.cs
diff --git a/src/Avalonia.Animation/FillMode.cs b/src/Avalonia.Base/Animation/FillMode.cs
similarity index 100%
rename from src/Avalonia.Animation/FillMode.cs
rename to src/Avalonia.Base/Animation/FillMode.cs
diff --git a/src/Avalonia.Base/Animation/IAnimation.cs b/src/Avalonia.Base/Animation/IAnimation.cs
new file mode 100644
index 0000000000..eda86ed106
--- /dev/null
+++ b/src/Avalonia.Base/Animation/IAnimation.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia.Metadata;
+
+namespace Avalonia.Animation
+{
+ ///
+ /// Interface for Animation objects
+ ///
+ [NotClientImplementable]
+ public interface IAnimation
+ {
+ ///
+ /// Apply the animation to the specified control and run it when produces true.
+ ///
+ IDisposable Apply(Animatable control, IClock? clock, IObservable match, Action? onComplete = null);
+
+ ///
+ /// Run the animation on the specified control.
+ ///
+ Task RunAsync(Animatable control, IClock clock, CancellationToken cancellationToken = default);
+ }
+}
diff --git a/src/Avalonia.Base/Animation/IAnimationSetter.cs b/src/Avalonia.Base/Animation/IAnimationSetter.cs
new file mode 100644
index 0000000000..8c4ba95517
--- /dev/null
+++ b/src/Avalonia.Base/Animation/IAnimationSetter.cs
@@ -0,0 +1,11 @@
+using Avalonia.Metadata;
+
+namespace Avalonia.Animation
+{
+ [NotClientImplementable]
+ public interface IAnimationSetter
+ {
+ AvaloniaProperty? Property { get; set; }
+ object? Value { get; set; }
+ }
+}
diff --git a/src/Avalonia.Base/Animation/IAnimator.cs b/src/Avalonia.Base/Animation/IAnimator.cs
new file mode 100644
index 0000000000..06ba8dc329
--- /dev/null
+++ b/src/Avalonia.Base/Animation/IAnimator.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Metadata;
+
+namespace Avalonia.Animation
+{
+ ///
+ /// Interface for Animator objects
+ ///
+ [NotClientImplementable]
+ public interface IAnimator : IList
+ {
+ ///
+ /// The target property.
+ ///
+ AvaloniaProperty? Property {get; set;}
+
+ ///
+ /// Applies the current KeyFrame group to the specified control.
+ ///
+ IDisposable? Apply(Animation animation, Animatable control, IClock? clock, IObservable match, Action? onComplete);
+ }
+}
diff --git a/src/Avalonia.Base/Animation/IClock.cs b/src/Avalonia.Base/Animation/IClock.cs
new file mode 100644
index 0000000000..7b3b7b3924
--- /dev/null
+++ b/src/Avalonia.Base/Animation/IClock.cs
@@ -0,0 +1,11 @@
+using System;
+using Avalonia.Metadata;
+
+namespace Avalonia.Animation
+{
+ [NotClientImplementable]
+ public interface IClock : IObservable
+ {
+ PlayState PlayState { get; set; }
+ }
+}
diff --git a/src/Avalonia.Base/Animation/IGlobalClock.cs b/src/Avalonia.Base/Animation/IGlobalClock.cs
new file mode 100644
index 0000000000..138dc07539
--- /dev/null
+++ b/src/Avalonia.Base/Animation/IGlobalClock.cs
@@ -0,0 +1,9 @@
+using Avalonia.Metadata;
+
+namespace Avalonia.Animation
+{
+ [NotClientImplementable]
+ public interface IGlobalClock : IClock
+ {
+ }
+}
diff --git a/src/Avalonia.Visuals/Animation/IPageTransition.cs b/src/Avalonia.Base/Animation/IPageTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/IPageTransition.cs
rename to src/Avalonia.Base/Animation/IPageTransition.cs
diff --git a/src/Avalonia.Base/Animation/ITransition.cs b/src/Avalonia.Base/Animation/ITransition.cs
new file mode 100644
index 0000000000..639b92ce35
--- /dev/null
+++ b/src/Avalonia.Base/Animation/ITransition.cs
@@ -0,0 +1,23 @@
+using System;
+using Avalonia.Metadata;
+
+namespace Avalonia.Animation
+{
+ ///
+ /// Interface for Transition objects.
+ ///
+ [NotClientImplementable]
+ public interface ITransition
+ {
+ ///
+ /// Applies the transition to the specified .
+ ///
+ IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue);
+
+ ///
+ /// Gets the property to be animated.
+ ///
+ AvaloniaProperty Property { get; set; }
+
+ }
+}
diff --git a/src/Avalonia.Animation/IterationCount.cs b/src/Avalonia.Base/Animation/IterationCount.cs
similarity index 100%
rename from src/Avalonia.Animation/IterationCount.cs
rename to src/Avalonia.Base/Animation/IterationCount.cs
diff --git a/src/Avalonia.Animation/IterationCountTypeConverter.cs b/src/Avalonia.Base/Animation/IterationCountTypeConverter.cs
similarity index 100%
rename from src/Avalonia.Animation/IterationCountTypeConverter.cs
rename to src/Avalonia.Base/Animation/IterationCountTypeConverter.cs
diff --git a/src/Avalonia.Animation/KeyFrame.cs b/src/Avalonia.Base/Animation/KeyFrame.cs
similarity index 100%
rename from src/Avalonia.Animation/KeyFrame.cs
rename to src/Avalonia.Base/Animation/KeyFrame.cs
diff --git a/src/Avalonia.Animation/KeyFrames.cs b/src/Avalonia.Base/Animation/KeyFrames.cs
similarity index 100%
rename from src/Avalonia.Animation/KeyFrames.cs
rename to src/Avalonia.Base/Animation/KeyFrames.cs
diff --git a/src/Avalonia.Animation/KeySpline.cs b/src/Avalonia.Base/Animation/KeySpline.cs
similarity index 100%
rename from src/Avalonia.Animation/KeySpline.cs
rename to src/Avalonia.Base/Animation/KeySpline.cs
diff --git a/src/Avalonia.Animation/KeySplineTypeConverter.cs b/src/Avalonia.Base/Animation/KeySplineTypeConverter.cs
similarity index 100%
rename from src/Avalonia.Animation/KeySplineTypeConverter.cs
rename to src/Avalonia.Base/Animation/KeySplineTypeConverter.cs
diff --git a/src/Avalonia.Base/Animation/PageSlide.cs b/src/Avalonia.Base/Animation/PageSlide.cs
new file mode 100644
index 0000000000..b22bc8b243
--- /dev/null
+++ b/src/Avalonia.Base/Animation/PageSlide.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia.Animation.Easings;
+using Avalonia.Media;
+using Avalonia.Styling;
+using Avalonia.VisualTree;
+
+namespace Avalonia.Animation
+{
+ ///
+ /// Transitions between two pages by sliding them horizontally or vertically.
+ ///
+ public class PageSlide : IPageTransition
+ {
+ ///
+ /// The axis on which the PageSlide should occur
+ ///
+ public enum SlideAxis
+ {
+ Horizontal,
+ Vertical
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PageSlide()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The duration of the animation.
+ /// The axis on which the animation should occur
+ public PageSlide(TimeSpan duration, SlideAxis orientation = SlideAxis.Horizontal)
+ {
+ Duration = duration;
+ Orientation = orientation;
+ }
+
+ ///
+ /// Gets the duration of the animation.
+ ///
+ public TimeSpan Duration { get; set; }
+
+ ///
+ /// Gets the duration of the animation.
+ ///
+ public SlideAxis Orientation { get; set; }
+
+ ///
+ /// Gets or sets element entrance easing.
+ ///
+ public Easing SlideInEasing { get; set; } = new LinearEasing();
+
+ ///
+ /// Gets or sets element exit easing.
+ ///
+ public Easing SlideOutEasing { get; set; } = new LinearEasing();
+
+ ///
+ public virtual async Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ var tasks = new List();
+ var parent = GetVisualParent(from, to);
+ var distance = Orientation == SlideAxis.Horizontal ? parent.Bounds.Width : parent.Bounds.Height;
+ var translateProperty = Orientation == SlideAxis.Horizontal ? TranslateTransform.XProperty : TranslateTransform.YProperty;
+
+ if (from != null)
+ {
+ var animation = new Animation
+ {
+ Easing = SlideOutEasing,
+ FillMode = FillMode.Forward,
+ Children =
+ {
+ new KeyFrame
+ {
+ Setters = { new Setter { Property = translateProperty, Value = 0d } },
+ Cue = new Cue(0d)
+ },
+ new KeyFrame
+ {
+ Setters =
+ {
+ new Setter
+ {
+ Property = translateProperty,
+ Value = forward ? -distance : distance
+ }
+ },
+ Cue = new Cue(1d)
+ }
+ },
+ Duration = Duration
+ };
+ tasks.Add(animation.RunAsync(from, null, cancellationToken));
+ }
+
+ if (to != null)
+ {
+ to.IsVisible = true;
+ var animation = new Animation
+ {
+ FillMode = FillMode.Forward,
+ Easing = SlideInEasing,
+ Children =
+ {
+ new KeyFrame
+ {
+ Setters =
+ {
+ new Setter
+ {
+ Property = translateProperty,
+ Value = forward ? distance : -distance
+ }
+ },
+ Cue = new Cue(0d)
+ },
+ new KeyFrame
+ {
+ Setters = { new Setter { Property = translateProperty, Value = 0d } },
+ Cue = new Cue(1d)
+ }
+ },
+ Duration = Duration
+ };
+ tasks.Add(animation.RunAsync(to, null, cancellationToken));
+ }
+
+ await Task.WhenAll(tasks);
+
+ if (from != null && !cancellationToken.IsCancellationRequested)
+ {
+ from.IsVisible = false;
+ }
+ }
+
+ ///
+ /// Gets the common visual parent of the two control.
+ ///
+ /// The from control.
+ /// The to control.
+ /// The common parent.
+ ///
+ /// The two controls do not share a common parent.
+ ///
+ ///
+ /// Any one of the parameters may be null, but not both.
+ ///
+ protected static IVisual GetVisualParent(IVisual? from, IVisual? to)
+ {
+ var p1 = (from ?? to)!.VisualParent;
+ var p2 = (to ?? from)!.VisualParent;
+
+ if (p1 != null && p2 != null && p1 != p2)
+ {
+ throw new ArgumentException("Controls for PageSlide must have same parent.");
+ }
+
+ return p1 ?? throw new InvalidOperationException("Cannot determine visual parent.");
+ }
+ }
+}
diff --git a/src/Avalonia.Animation/PlayState.cs b/src/Avalonia.Base/Animation/PlayState.cs
similarity index 100%
rename from src/Avalonia.Animation/PlayState.cs
rename to src/Avalonia.Base/Animation/PlayState.cs
diff --git a/src/Avalonia.Animation/PlaybackDirection.cs b/src/Avalonia.Base/Animation/PlaybackDirection.cs
similarity index 100%
rename from src/Avalonia.Animation/PlaybackDirection.cs
rename to src/Avalonia.Base/Animation/PlaybackDirection.cs
diff --git a/src/Avalonia.Visuals/Animation/RenderLoopClock.cs b/src/Avalonia.Base/Animation/RenderLoopClock.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/RenderLoopClock.cs
rename to src/Avalonia.Base/Animation/RenderLoopClock.cs
diff --git a/src/Avalonia.Animation/Transition.cs b/src/Avalonia.Base/Animation/Transition.cs
similarity index 100%
rename from src/Avalonia.Animation/Transition.cs
rename to src/Avalonia.Base/Animation/Transition.cs
diff --git a/src/Avalonia.Animation/TransitionInstance.cs b/src/Avalonia.Base/Animation/TransitionInstance.cs
similarity index 100%
rename from src/Avalonia.Animation/TransitionInstance.cs
rename to src/Avalonia.Base/Animation/TransitionInstance.cs
diff --git a/src/Avalonia.Animation/TransitionObservableBase.cs b/src/Avalonia.Base/Animation/TransitionObservableBase.cs
similarity index 100%
rename from src/Avalonia.Animation/TransitionObservableBase.cs
rename to src/Avalonia.Base/Animation/TransitionObservableBase.cs
diff --git a/src/Avalonia.Animation/Transitions.cs b/src/Avalonia.Base/Animation/Transitions.cs
similarity index 100%
rename from src/Avalonia.Animation/Transitions.cs
rename to src/Avalonia.Base/Animation/Transitions.cs
diff --git a/src/Avalonia.Visuals/Animation/Transitions/BoxShadowsTransition.cs b/src/Avalonia.Base/Animation/Transitions/BoxShadowsTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Transitions/BoxShadowsTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/BoxShadowsTransition.cs
diff --git a/src/Avalonia.Visuals/Animation/Transitions/BrushTransition.cs b/src/Avalonia.Base/Animation/Transitions/BrushTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Transitions/BrushTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/BrushTransition.cs
diff --git a/src/Avalonia.Visuals/Animation/Transitions/ColorTransition.cs b/src/Avalonia.Base/Animation/Transitions/ColorTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Transitions/ColorTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/ColorTransition.cs
diff --git a/src/Avalonia.Visuals/Animation/Transitions/CornerRadiusTransition.cs b/src/Avalonia.Base/Animation/Transitions/CornerRadiusTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Transitions/CornerRadiusTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/CornerRadiusTransition.cs
diff --git a/src/Avalonia.Animation/Transitions/DoubleTransition.cs b/src/Avalonia.Base/Animation/Transitions/DoubleTransition.cs
similarity index 100%
rename from src/Avalonia.Animation/Transitions/DoubleTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/DoubleTransition.cs
diff --git a/src/Avalonia.Animation/Transitions/FloatTransition.cs b/src/Avalonia.Base/Animation/Transitions/FloatTransition.cs
similarity index 100%
rename from src/Avalonia.Animation/Transitions/FloatTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/FloatTransition.cs
diff --git a/src/Avalonia.Animation/Transitions/IntegerTransition.cs b/src/Avalonia.Base/Animation/Transitions/IntegerTransition.cs
similarity index 100%
rename from src/Avalonia.Animation/Transitions/IntegerTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/IntegerTransition.cs
diff --git a/src/Avalonia.Visuals/Animation/Transitions/PointTransition.cs b/src/Avalonia.Base/Animation/Transitions/PointTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Transitions/PointTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/PointTransition.cs
diff --git a/src/Avalonia.Visuals/Animation/Transitions/RelativePointTransition.cs b/src/Avalonia.Base/Animation/Transitions/RelativePointTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Transitions/RelativePointTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/RelativePointTransition.cs
diff --git a/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs b/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs
new file mode 100644
index 0000000000..239f3aea08
--- /dev/null
+++ b/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia.Media;
+using Avalonia.Styling;
+
+namespace Avalonia.Animation;
+
+public class Rotate3DTransition: PageSlide
+{
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// How long the rotation should take place
+ /// The orientation of the rotation
+ /// Defines the depth of the 3D Effect. If null, depth will be calculated automatically from the width or height of the common parent of the visual being rotated
+ public Rotate3DTransition(TimeSpan duration, SlideAxis orientation = SlideAxis.Horizontal, double? depth = null)
+ : base(duration, orientation)
+ {
+ Depth = depth;
+ }
+
+ ///
+ /// Defines the depth of the 3D Effect. If null, depth will be calculated automatically from the width or height
+ /// of the common parent of the visual being rotated.
+ ///
+ public double? Depth { get; set; }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ public Rotate3DTransition() { }
+
+ ///
+ public override async Task Start(Visual? @from, Visual? to, bool forward, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ var tasks = new Task[from != null && to != null ? 2 : 1];
+ var parent = GetVisualParent(from, to);
+ var (rotateProperty, center) = Orientation switch
+ {
+ SlideAxis.Vertical => (Rotate3DTransform.AngleXProperty, parent.Bounds.Height),
+ SlideAxis.Horizontal => (Rotate3DTransform.AngleYProperty, parent.Bounds.Width),
+ _ => throw new ArgumentOutOfRangeException()
+ };
+
+ var depthSetter = new Setter {Property = Rotate3DTransform.DepthProperty, Value = Depth ?? center};
+ var centerZSetter = new Setter {Property = Rotate3DTransform.CenterZProperty, Value = -center / 2};
+
+ KeyFrame CreateKeyFrame(double cue, double rotation, int zIndex, bool isVisible = true) =>
+ new() {
+ Setters =
+ {
+ new Setter { Property = rotateProperty, Value = rotation },
+ new Setter { Property = Visual.ZIndexProperty, Value = zIndex },
+ new Setter { Property = Visual.IsVisibleProperty, Value = isVisible },
+ centerZSetter,
+ depthSetter
+ },
+ Cue = new Cue(cue)
+ };
+
+ if (from != null)
+ {
+ var animation = new Animation
+ {
+ Easing = SlideOutEasing,
+ Duration = Duration,
+ FillMode = FillMode.Forward,
+ Children =
+ {
+ CreateKeyFrame(0d, 0d, 2),
+ CreateKeyFrame(0.5d, 45d * (forward ? -1 : 1), 1),
+ CreateKeyFrame(1d, 90d * (forward ? -1 : 1), 1, isVisible: false)
+ }
+ };
+
+ tasks[0] = animation.RunAsync(from, null, cancellationToken);
+ }
+
+ if (to != null)
+ {
+ to.IsVisible = true;
+ var animation = new Animation
+ {
+ Easing = SlideInEasing,
+ Duration = Duration,
+ FillMode = FillMode.Forward,
+ Children =
+ {
+ CreateKeyFrame(0d, 90d * (forward ? 1 : -1), 1),
+ CreateKeyFrame(0.5d, 45d * (forward ? 1 : -1), 1),
+ CreateKeyFrame(1d, 0d, 2)
+ }
+ };
+
+ tasks[from != null ? 1 : 0] = animation.RunAsync(to, null, cancellationToken);
+ }
+
+ await Task.WhenAll(tasks);
+
+ if (!cancellationToken.IsCancellationRequested)
+ {
+ if (to != null)
+ {
+ to.ZIndex = 2;
+ }
+
+ if (from != null)
+ {
+ from.IsVisible = false;
+ from.ZIndex = 1;
+ }
+ }
+ }
+}
diff --git a/src/Avalonia.Visuals/Animation/Transitions/SizeTransition.cs b/src/Avalonia.Base/Animation/Transitions/SizeTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Transitions/SizeTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/SizeTransition.cs
diff --git a/src/Avalonia.Visuals/Animation/Transitions/ThicknessTransition.cs b/src/Avalonia.Base/Animation/Transitions/ThicknessTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Transitions/ThicknessTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/ThicknessTransition.cs
diff --git a/src/Avalonia.Visuals/Animation/Transitions/TransformOperationsTransition.cs b/src/Avalonia.Base/Animation/Transitions/TransformOperationsTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Transitions/TransformOperationsTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/TransformOperationsTransition.cs
diff --git a/src/Avalonia.Visuals/Animation/Transitions/VectorTransition.cs b/src/Avalonia.Base/Animation/Transitions/VectorTransition.cs
similarity index 100%
rename from src/Avalonia.Visuals/Animation/Transitions/VectorTransition.cs
rename to src/Avalonia.Base/Animation/Transitions/VectorTransition.cs
diff --git a/src/Avalonia.Animation/Utils/BounceEaseUtils.cs b/src/Avalonia.Base/Animation/Utils/BounceEaseUtils.cs
similarity index 100%
rename from src/Avalonia.Animation/Utils/BounceEaseUtils.cs
rename to src/Avalonia.Base/Animation/Utils/BounceEaseUtils.cs
diff --git a/src/Avalonia.Animation/Utils/EasingUtils.cs b/src/Avalonia.Base/Animation/Utils/EasingUtils.cs
similarity index 100%
rename from src/Avalonia.Animation/Utils/EasingUtils.cs
rename to src/Avalonia.Base/Animation/Utils/EasingUtils.cs
diff --git a/src/Avalonia.Base/ApiCompatBaseline.txt b/src/Avalonia.Base/ApiCompatBaseline.txt
index 4701a83175..7f378d2f65 100644
--- a/src/Avalonia.Base/ApiCompatBaseline.txt
+++ b/src/Avalonia.Base/ApiCompatBaseline.txt
@@ -1,3 +1,4 @@
Compat issues with assembly Avalonia.Base:
+MembersMustExist : Member 'public System.Int32 System.Int32 Avalonia.Threading.DispatcherPriority.value__' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Threading.IDispatcher.Post(System.Action, T, Avalonia.Threading.DispatcherPriority)' is present in the implementation but not in the contract.
-Total Issues: 1
+Total Issues: 2
diff --git a/src/Avalonia.Visuals/Assets/BiDi.trie b/src/Avalonia.Base/Assets/BiDi.trie
similarity index 100%
rename from src/Avalonia.Visuals/Assets/BiDi.trie
rename to src/Avalonia.Base/Assets/BiDi.trie
diff --git a/src/Avalonia.Visuals/Assets/GraphemeBreak.trie b/src/Avalonia.Base/Assets/GraphemeBreak.trie
similarity index 100%
rename from src/Avalonia.Visuals/Assets/GraphemeBreak.trie
rename to src/Avalonia.Base/Assets/GraphemeBreak.trie
diff --git a/src/Avalonia.Visuals/Assets/UnicodeData.trie b/src/Avalonia.Base/Assets/UnicodeData.trie
similarity index 100%
rename from src/Avalonia.Visuals/Assets/UnicodeData.trie
rename to src/Avalonia.Base/Assets/UnicodeData.trie
diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj
index 637b86d759..16a91b10d6 100644
--- a/src/Avalonia.Base/Avalonia.Base.csproj
+++ b/src/Avalonia.Base/Avalonia.Base.csproj
@@ -5,6 +5,9 @@
Avalonia
True
+
+
+
@@ -13,4 +16,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index 437339d3b2..1f14ddede4 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -5,6 +5,7 @@ using Avalonia.Data;
using Avalonia.Diagnostics;
using Avalonia.Logging;
using Avalonia.PropertyStore;
+using Avalonia.Reactive;
using Avalonia.Threading;
namespace Avalonia
@@ -15,13 +16,13 @@ namespace Avalonia
///
/// This class is analogous to DependencyObject in WPF.
///
- public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged, IValueSink
+ public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged
{
- private IAvaloniaObject? _inheritanceParent;
+ private AvaloniaObject? _inheritanceParent;
private List? _directBindings;
private PropertyChangedEventHandler? _inpcChanged;
private EventHandler? _propertyChanged;
- private List? _inheritanceChildren;
+ private List? _inheritanceChildren;
private ValueStore? _values;
private bool _batchUpdate;
@@ -58,7 +59,7 @@ namespace Avalonia
///
/// The inheritance parent.
///
- protected IAvaloniaObject? InheritanceParent
+ protected AvaloniaObject? InheritanceParent
{
get
{
@@ -320,14 +321,14 @@ namespace Avalonia
/// The property.
/// The value.
/// The priority of the value.
- public void SetValue(
+ public IDisposable? SetValue(
AvaloniaProperty property,
object? value,
BindingPriority priority = BindingPriority.LocalValue)
{
property = property ?? throw new ArgumentNullException(nameof(property));
- property.RouteSetValue(this, value, priority);
+ return property.RouteSetValue(this, value, priority);
}
///
@@ -385,6 +386,26 @@ namespace Avalonia
SetDirectValueUnchecked(property, value);
}
+ ///
+ /// Binds a to an observable.
+ ///
+ /// The property.
+ /// The observable.
+ /// The priority of the binding.
+ ///
+ /// A disposable which can be used to terminate the binding.
+ ///
+ public IDisposable Bind(
+ AvaloniaProperty property,
+ IObservable
/// The property change details.
- protected virtual void OnPropertyChangedCore(AvaloniaPropertyChangedEventArgs change)
+ protected virtual void OnPropertyChangedCore(AvaloniaPropertyChangedEventArgs change)
{
if (change.IsEffectiveValueChange)
{
@@ -652,7 +671,7 @@ namespace Avalonia
/// Called when a avalonia property changes on the object.
///
/// The property change details.
- protected virtual void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ protected virtual void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
}
@@ -843,7 +862,7 @@ namespace Avalonia
if (metadata.EnableDataValidation == true)
{
- UpdateDataValidation(property, value);
+ UpdateDataValidation(property, value.Type, value.Error);
}
}
diff --git a/src/Avalonia.Base/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
index 51237409bf..134e3b2ac7 100644
--- a/src/Avalonia.Base/AvaloniaObjectExtensions.cs
+++ b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
@@ -25,7 +25,7 @@ namespace Avalonia
}
///
- /// Gets an observable for a .
+ /// Gets an observable for an .
///
/// The object.
/// The property.
@@ -44,7 +44,7 @@ namespace Avalonia
}
///
- /// Gets an observable for a .
+ /// Gets an observable for an .
///
/// The object.
/// The property type.
@@ -64,7 +64,7 @@ namespace Avalonia
}
///
- /// Gets an observable for a .
+ /// Gets an observable for an .
///
/// The object.
/// The property.
@@ -85,7 +85,7 @@ namespace Avalonia
}
///
- /// Gets an observable for a .
+ /// Gets an observable for an .
///
/// The object.
/// The property type.
@@ -128,7 +128,7 @@ namespace Avalonia
}
///
- /// Gets a subject for a .
+ /// Gets a subject for an .
///
/// The object.
/// The property.
@@ -150,7 +150,7 @@ namespace Avalonia
}
///
- /// Gets a subject for a .
+ /// Gets a subject for an .
///
/// The property type.
/// The object.
@@ -230,30 +230,7 @@ namespace Avalonia
}
///
- /// Binds a to an observable.
- ///
- /// The object.
- /// The property.
- /// The observable.
- /// The priority of the binding.
- ///
- /// A disposable which can be used to terminate the binding.
- ///
- public static IDisposable Bind(
- this IAvaloniaObject target,
- AvaloniaProperty property,
- IObservable> source,
- BindingPriority priority = BindingPriority.LocalValue)
- {
- target = target ?? throw new ArgumentNullException(nameof(target));
- property = property ?? throw new ArgumentNullException(nameof(property));
- source = source ?? throw new ArgumentNullException(nameof(source));
-
- return property.RouteBind(target, source, priority);
- }
-
- ///
- /// Binds a to an observable.
+ /// Binds an to an observable.
///
/// The type of the property.
/// The object.
@@ -273,42 +250,22 @@ namespace Avalonia
property = property ?? throw new ArgumentNullException(nameof(property));
source = source ?? throw new ArgumentNullException(nameof(source));
- return property switch
+ if (target is AvaloniaObject ao)
{
- StyledPropertyBase styled => target.Bind(styled, source, priority),
- DirectPropertyBase direct => target.Bind(direct, source),
- _ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
- };
- }
+ return property switch
+ {
+ StyledPropertyBase styled => ao.Bind(styled, source, priority),
+ DirectPropertyBase direct => ao.Bind(direct, source),
+ _ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
+ };
+ }
- ///
- /// Binds a to an observable.
- ///
- /// The object.
- /// The property.
- /// The observable.
- /// The priority of the binding.
- ///
- /// A disposable which can be used to terminate the binding.
- ///
- public static IDisposable Bind(
- this IAvaloniaObject target,
- AvaloniaProperty property,
- IObservable