diff --git a/.gitignore b/.gitignore index 5539efd0..b3f7e22f 100644 --- a/.gitignore +++ b/.gitignore @@ -206,6 +206,9 @@ FakesAssemblies/ # Visual Studio 6 workspace options file *.opt +# Visual Studio editor config file +.editorconfig + # LightSwitch generated files GeneratedArtifacts/ _Pvt_Extensions/ @@ -234,4 +237,6 @@ msbuild.binlog LottieGenOutput-*/ # Visual Studio debugging configuration file. -launchSettings.json \ No newline at end of file +launchSettings.json + +Generated Files/ \ No newline at end of file diff --git a/Lottie-Windows-WinUI3-Controls/Lottie-Windows-WinUI3-Controls.csproj b/Lottie-Windows-WinUI3-Controls/Lottie-Windows-WinUI3-Controls.csproj new file mode 100644 index 00000000..a1b006a4 --- /dev/null +++ b/Lottie-Windows-WinUI3-Controls/Lottie-Windows-WinUI3-Controls.csproj @@ -0,0 +1,24 @@ + + + net7.0-windows10.0.19041.0 + Library + true + CommunityToolkit.WinUI.Lottie.Controls + WinUI3 Toolkit Windows Animations Lottie XAML + + enable + x64;x86;ARM64 + Microsoft + True + + + + + + + + + + + + diff --git a/Lottie-Windows-WinUI3-Controls/LottieVisualSourceWinUI.cs b/Lottie-Windows-WinUI3-Controls/LottieVisualSourceWinUI.cs new file mode 100644 index 00000000..0e8b0d8a --- /dev/null +++ b/Lottie-Windows-WinUI3-Controls/LottieVisualSourceWinUI.cs @@ -0,0 +1,219 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Threading.Tasks; +using CommunityToolkit.WinAppSDK.LottieIsland; +using CommunityToolkit.WinUI.Lottie; +using Microsoft.UI.Composition; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Windows.Foundation; +using Windows.Foundation.Metadata; +using Windows.Storage; +using Windows.Storage.Streams; + +namespace CommunityToolkit.WinUI.Lottie.Controls +{ + /// + /// An for a Lottie composition. This allows + /// a Lottie to be specified as the source for a . + /// + public sealed class LottieVisualSourceWinUI : DependencyObject, IDynamicAnimatedVisualSource + { + LottieVisualSource _lottieVisualSource; + + HashSet> _compositionInvalidatedEventTokenTable = new HashSet>(); + + /// + /// Gets the options for the . + /// + // Optimize Lotties by default. Optimization takes a little longer but usually produces much + // more efficient translations. The only reason someone would turn optimization off is if + // the time to translate is too high, but in that case the Lottie is probably going to perform + // so badly on the machine that it won't really be usable with our without optimization. + public static DependencyProperty OptionsProperty { get; } = + RegisterDp(nameof(Options), LottieVisualOptions.Optimize); + + /// + /// Gets the URI from which to load a JSON Lottie file. + /// + public static DependencyProperty UriSourceProperty { get; } = + RegisterDp(nameof(UriSource), null, + (owner, oldValue, newValue) => owner._lottieVisualSource.UriSource = newValue); + + static DependencyProperty RegisterDp(string propertyName, T defaultValue) => + DependencyProperty.Register(propertyName, typeof(T), typeof(LottieVisualSourceWinUI), new PropertyMetadata(defaultValue)); + + static DependencyProperty RegisterDp(string propertyName, T? defaultValue, Action callback) + where T : class + => + DependencyProperty.Register(propertyName, typeof(T), typeof(LottieVisualSourceWinUI), + new PropertyMetadata(defaultValue, (d, e) => callback((LottieVisualSourceWinUI)d, (T)e.OldValue, (T)e.NewValue))); + + /// + /// Initializes a new instance of the class. + /// + public LottieVisualSourceWinUI() + { + _lottieVisualSource = new LottieVisualSource(); + _lottieVisualSource.AnimatedVisualInvalidated += OnAnimatedVisualInvalidated; + } + + public LottieVisualSourceWinUI(LottieVisualSource lottieVisualSource) + { + _lottieVisualSource = lottieVisualSource; + _lottieVisualSource.AnimatedVisualInvalidated += OnAnimatedVisualInvalidated; + } + + /// + /// Gets or sets options for how the Lottie is loaded. + /// + public LottieVisualOptions Options + { + get => (LottieVisualOptions)GetValue(OptionsProperty); + set => SetValue(OptionsProperty, value); + } + + /// + /// Gets or sets the Uniform Resource Identifier (URI) of the JSON source file for this . + /// + public Uri UriSource + { + get => (Uri)GetValue(UriSourceProperty); + set => SetValue(UriSourceProperty, value); + } + + /// + /// Called by XAML to convert a string to an . + /// + /// The for the given url. + public static LottieVisualSourceWinUI? CreateFromString(string uri) + { + LottieVisualSource? lottieVisualSource = LottieVisualSource.CreateFromString(uri); + if (lottieVisualSource != null) + { + return new LottieVisualSourceWinUI(lottieVisualSource); + } + else + { + return new LottieVisualSourceWinUI(); + } + } + + /// + /// Sets the source for the . + /// + /// A stream containing the text of a JSON Lottie file encoded as UTF-8. + /// An that completes when the load completes or fails. + [Overload("SetSourceStreamAsync")] + public IAsyncAction SetSourceAsync(IInputStream stream) + { + return _lottieVisualSource.SetSourceAsync(stream); + } + + /// + /// Sets the source for the . + /// + /// A file that is a JSON Lottie file. + /// An that completes when the load completes or fails. + [Overload("SetSourceFileAsync")] + public IAsyncAction SetSourceAsync(StorageFile file) + { + return _lottieVisualSource.SetSourceAsync(file); + } + + /// + /// Sets the source for the . + /// + /// A URI that refers to a JSON Lottie file. + /// An that completes when the load completes or fails. + [DefaultOverload] + [Overload("SetSourceUriAsync")] + public IAsyncAction SetSourceAsync(Uri sourceUri) + { + return _lottieVisualSource.SetSourceAsync(sourceUri); + } + + /// + /// Implements . + /// + // TODO: currently explicitly implemented interfaces are causing a problem with .NET Native. Make them implicit for now. + public event TypedEventHandler AnimatedVisualInvalidated + { + add + { + _compositionInvalidatedEventTokenTable.Add(value); + } + + remove + { + _compositionInvalidatedEventTokenTable.Remove(value); + } + } + + /// + /// Sets a delegate that returns an for the given image uri. + /// If this is null, no images will be loaded from references to external images. + /// + /// Most Lottie files do not reference external images, but those that do + /// will refer to the files via a uri. It is up to the user of + /// to manage the loading of the image, and return an for + /// that image. Alternatively the delegate may return null, and the image will not be + /// displayed. + public void SetImageAssetHandler(ImageAssetHandler? imageAssetHandler) + { + _lottieVisualSource.SetImageAssetHandler(imageAssetHandler); + } + + /// + /// Implements . + /// + /// The that can be used as a factory for the resulting . + /// An optional object that may provide extra information about the result. + /// An . + // TODO: currently explicitly implemented interfaces are causing a problem with .NET Native. Make them implicit for now. + //bool IAnimatedVisualSource.TryCreateAnimatedVisual( + public IAnimatedVisual? TryCreateAnimatedVisual( + Compositor compositor, + out object? diagnostics) + { + if (_lottieVisualSource is null) + { + // No content has been loaded yet. + // Return an IAnimatedVisual that produces nothing. + diagnostics = null; + return null; + } + else + { + // Some content was loaded. Ask the factory to produce an + // IAnimatedVisual. If it returns null, the player will treat it + // as an error. + IAnimatedVisualFrameworkless? animatedVisual = _lottieVisualSource.TryCreateAnimatedVisual(compositor, out diagnostics); + if (animatedVisual != null) + { + return new LottieVisualWinUI(animatedVisual); + } + else + { + return null; + } + } + } + + private void OnAnimatedVisualInvalidated(LottieVisualSource? sender, object? args) + { + foreach (var v in _compositionInvalidatedEventTokenTable) + { + v.Invoke(this, null); + } + } + } +} \ No newline at end of file diff --git a/Lottie-Windows-WinUI3-Controls/LottieVisualWinUI.cs b/Lottie-Windows-WinUI3-Controls/LottieVisualWinUI.cs new file mode 100644 index 00000000..34094fa6 --- /dev/null +++ b/Lottie-Windows-WinUI3-Controls/LottieVisualWinUI.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Numerics; +using CommunityToolkit.WinAppSDK.LottieIsland; +using Microsoft.UI.Composition; +using Microsoft.UI.Xaml.Controls; +using WinRT; + +namespace CommunityToolkit.WinUI.Lottie.Controls +{ + /// + /// Simple wrapper to convert an to an + /// for a Lottie composition. This allows + /// a Lottie to be specified as the source for a . + /// + internal class LottieVisualWinUI : IAnimatedVisual + { + IAnimatedVisualFrameworkless _animatedVisual; + + internal LottieVisualWinUI(IAnimatedVisualFrameworkless animatedVisual) + { + _animatedVisual = animatedVisual; + } + + public TimeSpan Duration => _animatedVisual.Duration; + + public Visual RootVisual => _animatedVisual.RootVisual; + + public Vector2 Size => _animatedVisual.Size; + + public void Dispose() + { + _animatedVisual.As().Dispose(); + } + } +} diff --git a/Lottie-Windows.sln b/Lottie-Windows.sln index 5bbb5a05..3916a544 100644 --- a/Lottie-Windows.sln +++ b/Lottie-Windows.sln @@ -18,11 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "source", "source", "{AB232F source\README.md = source\README.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LottieViewer", "LottieViewer\LottieViewer.csproj", "{5120EFD7-A556-46BF-8D56-F65F1EF9A305}" - ProjectSection(ProjectDependencies) = postProject - {6AB50ED0-6273-4919-9ADE-50195664EF15} = {6AB50ED0-6273-4919-9ADE-50195664EF15} - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lottie-Windows-Uwp", "Lottie-Windows\Lottie-Windows-Uwp\Lottie-Windows-Uwp.csproj", "{E392BAD0-F936-4B64-A445-552597795CC7}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dlls", "dlls", "{C75BD686-21A6-4EB3-8D4B-D5A01C019C52}" @@ -40,6 +35,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LottieToWinComp.dll", "dlls EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{00D8BD2B-70A1-48EC-AC5E-CC40561F8972}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig LICENSE.md = LICENSE.md README.md = README.md EndProjectSection @@ -169,7 +165,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LottieGen.MsBuild", "Lottie EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lottie-Windows-WinUI3", "Lottie-Windows\Lottie-Windows-WinUI3\Lottie-Windows-WinUI3.csproj", "{C505CD2D-5D26-42EE-8FAA-41BB784821EF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LottieSamples", "LottieSamples\LottieSamples.csproj", "{6AB50ED0-6273-4919-9ADE-50195664EF15}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LottieWinRT", "LottieWinRT\LottieWinRT.csproj", "{DDA0D223-4B59-455D-A8B1-CFAE59523FFB}" + ProjectSection(ProjectDependencies) = postProject + {9BA7A2F2-B723-458B-A575-3F726D271465} = {9BA7A2F2-B723-458B-A575-3F726D271465} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LottieIsland", "LottieIsland\LottieIsland.vcxproj", "{9BA7A2F2-B723-458B-A575-3F726D271465}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LottieIslandProjection", "LottieIslandProjection\LottieIslandProjection.csproj", "{D2DDC0A0-FD88-4053-9EA2-4233477D8477}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleLottieIslandApp", "SimpleLottieIslandApp\SimpleLottieIslandApp.vcxproj", "{350A5EC2-B156-4AAF-9D80-A864C76BA0C5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lottie-Windows-WinUI3-Controls", "Lottie-Windows-WinUI3-Controls\Lottie-Windows-WinUI3-Controls.csproj", "{A896C58F-1A1D-49A5-9044-75312051C455}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -190,45 +197,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|Any CPU.ActiveCfg = BETA|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|ARM.ActiveCfg = BETA|ARM - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|ARM.Build.0 = BETA|ARM - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|ARM.Deploy.0 = BETA|ARM - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|ARM64.ActiveCfg = BETA|ARM64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|ARM64.Build.0 = BETA|ARM64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|ARM64.Deploy.0 = BETA|ARM64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|x64.ActiveCfg = BETA|x64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|x64.Build.0 = BETA|x64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|x64.Deploy.0 = BETA|x64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|x86.ActiveCfg = BETA|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|x86.Build.0 = BETA|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|x86.Deploy.0 = BETA|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|Any CPU.ActiveCfg = Debug|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|ARM.ActiveCfg = Debug|ARM - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|ARM.Build.0 = Debug|ARM - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|ARM.Deploy.0 = Debug|ARM - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|ARM64.Build.0 = Debug|ARM64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|ARM64.Deploy.0 = Debug|ARM64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|x64.ActiveCfg = Debug|x64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|x64.Build.0 = Debug|x64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|x64.Deploy.0 = Debug|x64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|x86.ActiveCfg = Debug|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|x86.Build.0 = Debug|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Debug|x86.Deploy.0 = Debug|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|Any CPU.ActiveCfg = Release|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|ARM.ActiveCfg = Release|ARM - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|ARM.Build.0 = Release|ARM - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|ARM.Deploy.0 = Release|ARM - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|ARM64.ActiveCfg = Release|ARM64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|ARM64.Build.0 = Release|ARM64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|ARM64.Deploy.0 = Release|ARM64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|x64.ActiveCfg = Release|x64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|x64.Build.0 = Release|x64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|x64.Deploy.0 = Release|x64 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|x86.ActiveCfg = Release|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|x86.Build.0 = Release|x86 - {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.Release|x86.Deploy.0 = Release|x86 {E392BAD0-F936-4B64-A445-552597795CC7}.BETA|Any CPU.ActiveCfg = Release|Any CPU {E392BAD0-F936-4B64-A445-552597795CC7}.BETA|ARM.ActiveCfg = Release|Any CPU {E392BAD0-F936-4B64-A445-552597795CC7}.BETA|ARM64.ActiveCfg = Release|Any CPU @@ -540,79 +508,193 @@ Global {192FBD28-8531-4607-A17C-44A1A51A1565}.Release|x86.ActiveCfg = Release|Any CPU {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|Any CPU.ActiveCfg = Debug|x64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|Any CPU.Build.0 = Debug|x64 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|ARM.ActiveCfg = Debug|x64 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|ARM.Build.0 = Debug|x64 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|ARM64.ActiveCfg = Debug|x64 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|ARM64.Build.0 = Debug|x64 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|ARM.ActiveCfg = Release|x64 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|ARM.Build.0 = Release|x64 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|ARM64.ActiveCfg = Debug|ARM64 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|ARM64.Build.0 = Debug|ARM64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|x64.ActiveCfg = Debug|x64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|x64.Build.0 = Debug|x64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|x86.ActiveCfg = Debug|x86 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.BETA|x86.Build.0 = Debug|x86 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|Any CPU.ActiveCfg = Debug|x64 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|Any CPU.Build.0 = Debug|x64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|ARM.ActiveCfg = Debug|x64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|ARM.Build.0 = Debug|x64 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|ARM64.ActiveCfg = Debug|x64 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|ARM64.Build.0 = Debug|x64 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|ARM64.Build.0 = Debug|ARM64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|x64.ActiveCfg = Debug|x64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|x64.Build.0 = Debug|x64 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|x86.ActiveCfg = Debug|Any CPU - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|x86.Build.0 = Debug|Any CPU - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|Any CPU.Build.0 = Release|Any CPU + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|x86.ActiveCfg = Debug|x86 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Debug|x86.Build.0 = Debug|x86 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|Any CPU.ActiveCfg = Release|x64 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|Any CPU.Build.0 = Release|x64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|ARM.ActiveCfg = Release|x64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|ARM.Build.0 = Release|x64 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|ARM64.ActiveCfg = Release|x64 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|ARM64.Build.0 = Release|x64 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|ARM64.ActiveCfg = Release|ARM64 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|ARM64.Build.0 = Release|ARM64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|x64.ActiveCfg = Release|x64 {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|x64.Build.0 = Release|x64 - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|x86.ActiveCfg = Release|Any CPU - {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|x86.Build.0 = Release|Any CPU - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|Any CPU.ActiveCfg = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|Any CPU.Build.0 = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|Any CPU.Deploy.0 = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|ARM.ActiveCfg = Debug|ARM - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|ARM.Build.0 = Debug|ARM - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|ARM.Deploy.0 = Debug|ARM - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|ARM64.ActiveCfg = Debug|ARM64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|ARM64.Build.0 = Debug|ARM64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|ARM64.Deploy.0 = Debug|ARM64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|x64.ActiveCfg = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|x64.Build.0 = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|x64.Deploy.0 = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|x86.ActiveCfg = Debug|x86 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|x86.Build.0 = Debug|x86 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.BETA|x86.Deploy.0 = Debug|x86 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|Any CPU.ActiveCfg = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|Any CPU.Build.0 = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|Any CPU.Deploy.0 = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|ARM.ActiveCfg = Debug|ARM - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|ARM.Build.0 = Debug|ARM - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|ARM.Deploy.0 = Debug|ARM - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|ARM64.Build.0 = Debug|ARM64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|ARM64.Deploy.0 = Debug|ARM64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|x64.ActiveCfg = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|x64.Build.0 = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|x64.Deploy.0 = Debug|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|x86.ActiveCfg = Debug|x86 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|x86.Build.0 = Debug|x86 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Debug|x86.Deploy.0 = Debug|x86 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|Any CPU.ActiveCfg = Release|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|Any CPU.Build.0 = Release|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|Any CPU.Deploy.0 = Release|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|ARM.ActiveCfg = Release|ARM - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|ARM.Build.0 = Release|ARM - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|ARM.Deploy.0 = Release|ARM - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|ARM64.ActiveCfg = Release|ARM64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|ARM64.Build.0 = Release|ARM64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|ARM64.Deploy.0 = Release|ARM64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|x64.ActiveCfg = Release|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|x64.Build.0 = Release|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|x64.Deploy.0 = Release|x64 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|x86.ActiveCfg = Release|x86 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|x86.Build.0 = Release|x86 - {6AB50ED0-6273-4919-9ADE-50195664EF15}.Release|x86.Deploy.0 = Release|x86 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|x86.ActiveCfg = Release|x86 + {C505CD2D-5D26-42EE-8FAA-41BB784821EF}.Release|x86.Build.0 = Release|x86 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.BETA|Any CPU.ActiveCfg = Debug|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.BETA|Any CPU.Build.0 = Debug|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.BETA|ARM.ActiveCfg = Release|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.BETA|ARM.Build.0 = Release|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.BETA|ARM64.ActiveCfg = Debug|ARM64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.BETA|ARM64.Build.0 = Debug|ARM64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.BETA|x64.ActiveCfg = Debug|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.BETA|x64.Build.0 = Debug|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.BETA|x86.ActiveCfg = Debug|x86 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.BETA|x86.Build.0 = Debug|x86 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Debug|Any CPU.ActiveCfg = Debug|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Debug|Any CPU.Build.0 = Debug|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Debug|ARM.ActiveCfg = Debug|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Debug|ARM.Build.0 = Debug|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Debug|ARM64.Build.0 = Debug|ARM64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Debug|x64.ActiveCfg = Debug|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Debug|x64.Build.0 = Debug|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Debug|x86.ActiveCfg = Debug|x86 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Debug|x86.Build.0 = Debug|x86 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Release|Any CPU.ActiveCfg = Release|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Release|Any CPU.Build.0 = Release|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Release|ARM.ActiveCfg = Release|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Release|ARM.Build.0 = Release|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Release|ARM64.ActiveCfg = Release|ARM64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Release|ARM64.Build.0 = Release|ARM64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Release|x64.ActiveCfg = Release|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Release|x64.Build.0 = Release|x64 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Release|x86.ActiveCfg = Release|x86 + {DDA0D223-4B59-455D-A8B1-CFAE59523FFB}.Release|x86.Build.0 = Release|x86 + {9BA7A2F2-B723-458B-A575-3F726D271465}.BETA|Any CPU.ActiveCfg = Debug|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.BETA|Any CPU.Build.0 = Debug|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.BETA|ARM.ActiveCfg = Release|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.BETA|ARM.Build.0 = Release|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.BETA|ARM64.ActiveCfg = Debug|ARM64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.BETA|ARM64.Build.0 = Debug|ARM64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.BETA|x64.ActiveCfg = Debug|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.BETA|x64.Build.0 = Debug|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.BETA|x86.ActiveCfg = Debug|Win32 + {9BA7A2F2-B723-458B-A575-3F726D271465}.BETA|x86.Build.0 = Debug|Win32 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Debug|Any CPU.ActiveCfg = Debug|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Debug|Any CPU.Build.0 = Debug|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Debug|ARM.ActiveCfg = Debug|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Debug|ARM.Build.0 = Debug|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Debug|ARM64.Build.0 = Debug|ARM64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Debug|x64.ActiveCfg = Debug|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Debug|x64.Build.0 = Debug|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Debug|x86.ActiveCfg = Debug|Win32 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Debug|x86.Build.0 = Debug|Win32 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Release|Any CPU.ActiveCfg = Release|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Release|Any CPU.Build.0 = Release|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Release|ARM.ActiveCfg = Release|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Release|ARM.Build.0 = Release|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Release|ARM64.ActiveCfg = Release|ARM64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Release|ARM64.Build.0 = Release|ARM64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Release|x64.ActiveCfg = Release|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Release|x64.Build.0 = Release|x64 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Release|x86.ActiveCfg = Release|Win32 + {9BA7A2F2-B723-458B-A575-3F726D271465}.Release|x86.Build.0 = Release|Win32 + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.BETA|Any CPU.ActiveCfg = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.BETA|Any CPU.Build.0 = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.BETA|ARM.ActiveCfg = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.BETA|ARM.Build.0 = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.BETA|ARM64.ActiveCfg = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.BETA|ARM64.Build.0 = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.BETA|x64.ActiveCfg = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.BETA|x64.Build.0 = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.BETA|x86.ActiveCfg = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.BETA|x86.Build.0 = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Debug|ARM.ActiveCfg = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Debug|ARM.Build.0 = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Debug|ARM64.Build.0 = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Debug|x64.ActiveCfg = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Debug|x64.Build.0 = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Debug|x86.ActiveCfg = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Debug|x86.Build.0 = Debug|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Release|Any CPU.Build.0 = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Release|ARM.ActiveCfg = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Release|ARM.Build.0 = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Release|ARM64.ActiveCfg = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Release|ARM64.Build.0 = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Release|x64.ActiveCfg = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Release|x64.Build.0 = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Release|x86.ActiveCfg = Release|Any CPU + {D2DDC0A0-FD88-4053-9EA2-4233477D8477}.Release|x86.Build.0 = Release|Any CPU + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|Any CPU.ActiveCfg = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|ARM.ActiveCfg = Release|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|ARM.Build.0 = Release|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|ARM.Deploy.0 = Release|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|ARM64.ActiveCfg = Debug|ARM64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|ARM64.Build.0 = Debug|ARM64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|ARM64.Deploy.0 = Debug|ARM64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|x64.ActiveCfg = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|x64.Build.0 = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|x64.Deploy.0 = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|x86.ActiveCfg = Debug|Win32 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|x86.Build.0 = Debug|Win32 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.BETA|x86.Deploy.0 = Debug|Win32 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|Any CPU.ActiveCfg = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|ARM.ActiveCfg = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|ARM.Build.0 = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|ARM.Deploy.0 = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|ARM64.Build.0 = Debug|ARM64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|x64.ActiveCfg = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|x64.Build.0 = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|x64.Deploy.0 = Debug|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|x86.ActiveCfg = Debug|Win32 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|x86.Build.0 = Debug|Win32 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Debug|x86.Deploy.0 = Debug|Win32 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|Any CPU.ActiveCfg = Release|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|ARM.ActiveCfg = Release|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|ARM.Build.0 = Release|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|ARM.Deploy.0 = Release|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|ARM64.ActiveCfg = Release|ARM64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|ARM64.Build.0 = Release|ARM64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|ARM64.Deploy.0 = Release|ARM64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|x64.ActiveCfg = Release|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|x64.Build.0 = Release|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|x64.Deploy.0 = Release|x64 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|x86.ActiveCfg = Release|Win32 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|x86.Build.0 = Release|Win32 + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5}.Release|x86.Deploy.0 = Release|Win32 + {A896C58F-1A1D-49A5-9044-75312051C455}.BETA|Any CPU.ActiveCfg = Debug|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.BETA|Any CPU.Build.0 = Debug|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.BETA|ARM.ActiveCfg = Release|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.BETA|ARM.Build.0 = Release|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.BETA|ARM64.ActiveCfg = Debug|ARM64 + {A896C58F-1A1D-49A5-9044-75312051C455}.BETA|ARM64.Build.0 = Debug|ARM64 + {A896C58F-1A1D-49A5-9044-75312051C455}.BETA|x64.ActiveCfg = Debug|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.BETA|x64.Build.0 = Debug|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.BETA|x86.ActiveCfg = Debug|x86 + {A896C58F-1A1D-49A5-9044-75312051C455}.BETA|x86.Build.0 = Debug|x86 + {A896C58F-1A1D-49A5-9044-75312051C455}.Debug|Any CPU.ActiveCfg = Debug|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Debug|Any CPU.Build.0 = Debug|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Debug|ARM.ActiveCfg = Debug|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Debug|ARM.Build.0 = Debug|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Debug|ARM64.Build.0 = Debug|ARM64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Debug|x64.ActiveCfg = Debug|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Debug|x64.Build.0 = Debug|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Debug|x86.ActiveCfg = Debug|x86 + {A896C58F-1A1D-49A5-9044-75312051C455}.Debug|x86.Build.0 = Debug|x86 + {A896C58F-1A1D-49A5-9044-75312051C455}.Release|Any CPU.ActiveCfg = Release|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Release|Any CPU.Build.0 = Release|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Release|ARM.ActiveCfg = Release|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Release|ARM.Build.0 = Release|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Release|ARM64.ActiveCfg = Release|ARM64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Release|ARM64.Build.0 = Release|ARM64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Release|x64.ActiveCfg = Release|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Release|x64.Build.0 = Release|x64 + {A896C58F-1A1D-49A5-9044-75312051C455}.Release|x86.ActiveCfg = Release|x86 + {A896C58F-1A1D-49A5-9044-75312051C455}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -665,21 +747,6 @@ Global source\WinUIXamlMediaData\WinUIXamlMediaData.projitems*{30059ca7-0745-4eec-8d11-b14850a70c98}*SharedItemsImports = 13 source\YamlData\YamlData.projitems*{39c6b7f3-5e75-4019-82ab-00fd8a0a06e2}*SharedItemsImports = 13 source\LottieReader\LottieReader.projitems*{4e7d8957-3f5f-46e1-99a8-2012b806c9b0}*SharedItemsImports = 13 - source\Animatables\Animatables.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\CompMetadata\CompMetadata.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\DotLottie\DotLottie.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\GenericData\GenericData.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\LottieData\LottieData.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\LottieMetadata\LottieMetadata.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\LottieReader\LottieReader.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\LottieToWinComp\LottieToWinComp.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\Lottie\Lottie.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\NullablesAttributes\NullablesAttributes.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\UIData\UIData.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\WinCompData\WinCompData.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\WinStorageStreamsData\WinStorageStreamsData.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\WinUIXamlMediaData\WinUIXamlMediaData.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 - source\YamlData\YamlData.projitems*{5120efd7-a556-46bf-8d56-f65f1ef9a305}*SharedItemsImports = 4 source\LottieData\LottieData.projitems*{6221591a-e8f4-4a5e-8f0c-2651c24ad495}*SharedItemsImports = 5 source\WinCompData\WinCompData.projitems*{68317393-f5a5-4b2c-918a-688db2c10f54}*SharedItemsImports = 5 source\Animatables\Animatables.projitems*{6984af37-d580-4087-806b-480a04f2df77}*SharedItemsImports = 5 @@ -698,7 +765,6 @@ Global source\WinStorageStreamsData\WinStorageStreamsData.projitems*{6984af37-d580-4087-806b-480a04f2df77}*SharedItemsImports = 5 source\WinUIXamlMediaData\WinUIXamlMediaData.projitems*{6984af37-d580-4087-806b-480a04f2df77}*SharedItemsImports = 5 source\YamlData\YamlData.projitems*{6984af37-d580-4087-806b-480a04f2df77}*SharedItemsImports = 5 - source\NullablesAttributes\NullablesAttributes.projitems*{6ab50ed0-6273-4919-9ade-50195664ef15}*SharedItemsImports = 4 source\DotLottie\DotLottie.projitems*{7012420d-624c-4bd4-a1d2-1c6c1655ed3a}*SharedItemsImports = 13 source\UIData\UIData.projitems*{74601e6c-2dfe-4842-b170-047941abff2c}*SharedItemsImports = 13 source\LottieGen\LottieGen.projitems*{7654a857-9a99-4185-9f8e-dd0ce662af23}*SharedItemsImports = 13 diff --git a/Lottie-Windows/Lottie-Windows-WinUI3/Lottie-Windows-WinUI3.csproj b/Lottie-Windows/Lottie-Windows-WinUI3/Lottie-Windows-WinUI3.csproj index ec59b7c9..74b74ec8 100644 --- a/Lottie-Windows/Lottie-Windows-WinUI3/Lottie-Windows-WinUI3.csproj +++ b/Lottie-Windows/Lottie-Windows-WinUI3/Lottie-Windows-WinUI3.csproj @@ -1,7 +1,7 @@  - net7.0-windows10.0.18362.0 + net7.0-windows10.0.19041.0 true Library @@ -9,6 +9,7 @@ WinUI3 Toolkit Windows Animations Lottie XAML enable + x64;x86;ARM64 Microsoft WINAPPSDK True @@ -16,7 +17,12 @@ - + + + + + + diff --git a/LottieIsland/AutomationBase.cpp b/LottieIsland/AutomationBase.cpp new file mode 100644 index 00000000..3e248dfe --- /dev/null +++ b/LottieIsland/AutomationBase.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "AutomationBase.h" + +namespace AutomationHelpers +{ + +void AutomationBase::RemoveHandler( + IAutomationCallbackHandler const* const handler) +{ + std::unique_lock lock{ m_mutex }; + + auto iterator = std::remove_if( + m_handlers.begin(), m_handlers.end(), [handler](auto const& handlerEntry) + { + return handlerEntry.Match(handler); + }); + + m_handlers.erase(iterator, m_handlers.end()); +} + +void AutomationBase::AddHandler( + AutomationCallbackHandlerType const& type, + IAutomationCallbackHandler* const handler) +{ + // Remove any existing handler of the same type. + auto iterator = std::remove_if( + m_handlers.begin(), m_handlers.end(), [type](auto const& handlerEntry) + { + return handlerEntry.Match(type); + }); + + m_handlers.erase(iterator, m_handlers.end()); + + if (nullptr != handler) + { + m_handlers.emplace_back(AutomationCallbackHandlerEntry{ type, handler }); + } +} + +} \ No newline at end of file diff --git a/LottieIsland/AutomationBase.h b/LottieIsland/AutomationBase.h new file mode 100644 index 00000000..7571dce7 --- /dev/null +++ b/LottieIsland/AutomationBase.h @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include +#include "AutomationCallbackHandler.h" + +namespace AutomationHelpers +{ + +struct AutomationBase : winrt::implements +{ + [[nodiscard]] winrt::weak_ref GetWeak() const noexcept + { + try + { + return const_cast(this)->get_weak(); + } + catch (...) {} + return nullptr; + } + + template + [[nodiscard]] inline static winrt::com_ptr LockWeak( + winrt::weak_ref const& weakRef) noexcept + { + static_assert(std::is_base_of_v); + + try + { + if (nullptr != weakRef) + { + winrt::com_ptr weakRefGet = weakRef.get(); + if (nullptr != weakRefGet) + { + winrt::com_ptr strongRef{ nullptr }; + strongRef.copy_from(static_cast(weakRefGet.get())); + return strongRef; + } + } + } + catch (...) {} + return nullptr; + } + + template + [[nodiscard]] winrt::com_ptr GetStrong() const noexcept + { + static_assert(std::is_base_of_v); + + try + { + return static_cast(const_cast(this))->get_strong(); + } + catch (...) {} + return nullptr; + } + + template + [[nodiscard]] IUnknown* GetIUnknown() const noexcept + { + static_assert(std::is_base_of_v); + + try + { + return GetStrong().as().get(); + } + catch (...) {} + return nullptr; + } + + void RemoveHandler( + IAutomationCallbackHandler const* const handler); + +protected: + void AddHandler( + AutomationCallbackHandlerType const& type, + IAutomationCallbackHandler* const handler); + + template + [[nodiscard]] HandlerT* GetHandler( + AutomationCallbackHandlerType const& type) const + { + static_assert(std::is_base_of_v); + + auto iterator = std::find_if( + m_handlers.cbegin(), m_handlers.cend(), [&type](auto const& handlerEntry) + { + return handlerEntry.Match(type); + }); + + return (m_handlers.cend() != iterator) ? iterator->Get() : nullptr; + } + + mutable std::mutex m_mutex{}; + +private: + std::vector m_handlers{}; +}; + +} \ No newline at end of file diff --git a/LottieIsland/AutomationCallbackHandler.h b/LottieIsland/AutomationCallbackHandler.h new file mode 100644 index 00000000..0d720d0a --- /dev/null +++ b/LottieIsland/AutomationCallbackHandler.h @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include +#include +#include + +namespace AutomationHelpers +{ + +enum class AutomationCallbackHandlerType : unsigned char +{ + None, + Fragment, + FragmentRoot, + Invoke +}; + +struct IAutomationCallbackHandler +{ + virtual ~IAutomationCallbackHandler() noexcept = default; +}; + +struct IAutomationFragmentCallbackHandler : IAutomationCallbackHandler +{ + virtual winrt::Windows::Graphics::RectInt32 GetBoundingRectangleInScreenSpaceForAutomation( + ::IUnknown const* const sender) const = 0; + + virtual void HandleSetFocusForAutomation( + ::IUnknown const* const sender) = 0; +}; + +struct IAutomationFragmentRootCallbackHandler : IAutomationCallbackHandler +{ + virtual winrt::com_ptr<::IRawElementProviderFragment> GetFragmentFromPointForAutomation( + double x, + double y, + ::IUnknown const* const sender) const = 0; + + virtual winrt::com_ptr<::IRawElementProviderFragment> GetFragmentInFocusForAutomation( + ::IUnknown const* const sender) const = 0; +}; + +struct IAutomationInvokeCallbackHandler : IAutomationCallbackHandler +{ + virtual void HandleInvokeForAutomation( + ::IUnknown const* const sender) = 0; +}; + +struct AutomationCallbackHandlerEntry +{ + explicit AutomationCallbackHandlerEntry( + AutomationCallbackHandlerType const& type, + IAutomationCallbackHandler* const handler) : + _type{ type }, _handler{ handler } {} + + bool Match( + AutomationCallbackHandlerType const& type) const { return type == _type; } + + bool Match( + IAutomationCallbackHandler const* const handler) const { return handler == _handler; } + + template + DerivedT* Get() const + { + static_assert(std::is_base_of_v); + return static_cast(_handler); + } + +private: + AutomationCallbackHandlerType _type{ AutomationCallbackHandlerType::None }; + IAutomationCallbackHandler* _handler{ nullptr }; +}; + +} \ No newline at end of file diff --git a/LottieIsland/AutomationCallbackRevoker.h b/LottieIsland/AutomationCallbackRevoker.h new file mode 100644 index 00000000..6ceb0799 --- /dev/null +++ b/LottieIsland/AutomationCallbackRevoker.h @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "AutomationBase.h" + +namespace AutomationHelpers +{ + +struct AutomationCallbackRevoker +{ + [[nodiscard]] static std::unique_ptr Create( + winrt::weak_ref const& automationObject, + IAutomationCallbackHandler* const handler) noexcept + { + try + { + auto newRevoker = std::make_unique(); + newRevoker->Initialize(automationObject, handler); + return newRevoker; + } + catch (...) {} + return nullptr; + } + + explicit AutomationCallbackRevoker() noexcept = default; + + ~AutomationCallbackRevoker() noexcept + { + if (auto strongAutomationObject = _automationObject.get()) + { + if (nullptr != _handler) + { + strongAutomationObject->RemoveHandler(_handler); + } + } + } + + // Disable move and copy. + explicit AutomationCallbackRevoker(AutomationCallbackRevoker const&) = delete; + explicit AutomationCallbackRevoker(AutomationCallbackRevoker&&) = delete; + AutomationCallbackRevoker& operator=(AutomationCallbackRevoker const&) = delete; + AutomationCallbackRevoker& operator=(AutomationCallbackRevoker&&) = delete; + +private: + void Initialize( + winrt::weak_ref const& automationObject, + IAutomationCallbackHandler* const handler) + { + _automationObject = automationObject; + _handler = handler; + } + + winrt::weak_ref _automationObject{ nullptr }; + IAutomationCallbackHandler* _handler{ nullptr }; +}; + +} \ No newline at end of file diff --git a/LottieIsland/AutomationElement.cpp b/LottieIsland/AutomationElement.cpp new file mode 100644 index 00000000..6c117a16 --- /dev/null +++ b/LottieIsland/AutomationElement.cpp @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "AutomationElement.h" +#include + +namespace AutomationHelpers +{ + +HRESULT __stdcall AutomationElement::get_ProviderOptions( + _Out_ ::ProviderOptions* providerOptions) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != providerOptions) + { + *providerOptions = m_providerOptions; + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +HRESULT __stdcall AutomationElement::GetPatternProvider( + _In_ PATTERNID patternId, + _COM_Outptr_opt_result_maybenull_ ::IUnknown** patternProvider) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != patternProvider) + { + *patternProvider = nullptr; + switch (patternId) + { + case UIA_InvokePatternId: + { + if (auto invokeProvider = get_strong().try_as<::IInvokeProvider>()) + { + invokeProvider.as<::IUnknown>().copy_to(patternProvider); + } + break; + } + } + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +HRESULT __stdcall AutomationElement::GetPropertyValue( + _In_ PROPERTYID propertyId, + _Out_ VARIANT* propertyValue) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != propertyValue) + { + ::VariantInit(propertyValue); + switch (propertyId) + { + case UIA_NamePropertyId: + { + propertyValue->bstrVal = wil::make_bstr(m_name.c_str()).release(); + propertyValue->vt = VT_BSTR; + break; + } + + case UIA_IsContentElementPropertyId: + { + propertyValue->boolVal = m_isContent ? VARIANT_TRUE : VARIANT_FALSE; + propertyValue->vt = VT_BOOL; + break; + } + + case UIA_IsControlElementPropertyId: + { + propertyValue->boolVal = m_isControl ? VARIANT_TRUE : VARIANT_FALSE; + propertyValue->vt = VT_BOOL; + break; + } + + case UIA_ControlTypePropertyId: + { + if (m_isControl) + { + propertyValue->vt = VT_I4; + propertyValue->lVal = m_uiaControlTypeId; + } + break; + } + } + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +HRESULT __stdcall AutomationElement::get_HostRawElementProvider( + _COM_Outptr_opt_result_maybenull_ ::IRawElementProviderSimple** hostRawElementProviderSimple) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != hostRawElementProviderSimple) + { + m_hostProvider.copy_to(hostRawElementProviderSimple); + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +} \ No newline at end of file diff --git a/LottieIsland/AutomationElement.h b/LottieIsland/AutomationElement.h new file mode 100644 index 00000000..bea39ce0 --- /dev/null +++ b/LottieIsland/AutomationElement.h @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "AutomationBase.h" + +namespace AutomationHelpers +{ + +struct AutomationElement : winrt::implements +{ + // Settable properties. + void ProviderOptions(::ProviderOptions const& providerOptions) { std::unique_lock lock{ m_mutex }; m_providerOptions = providerOptions; } + void Name(std::wstring_view const& name) { std::unique_lock lock{ m_mutex }; m_name = name; } + void IsContent(bool const& isContent) { std::unique_lock lock{ m_mutex }; m_isContent = isContent; } + void IsControl(bool const& isControl) { std::unique_lock lock{ m_mutex }; m_isControl = isControl; } + void UiaControlTypeId(long const& uiaControlTypeId) { std::unique_lock lock{ m_mutex }; m_uiaControlTypeId = uiaControlTypeId; } + void HostProvider(winrt::com_ptr<::IRawElementProviderSimple> const& hostProvider) { std::unique_lock lock{ m_mutex }; m_hostProvider = hostProvider; } + + // IRawElementProviderSimple implementation. + HRESULT __stdcall get_ProviderOptions( + _Out_ ::ProviderOptions* providerOptions) final override; + + HRESULT __stdcall GetPatternProvider( + _In_ PATTERNID patternId, + _COM_Outptr_opt_result_maybenull_ ::IUnknown** patternProvider) final override; + + HRESULT __stdcall GetPropertyValue( + _In_ PROPERTYID propertyId, + _Out_ VARIANT* propertyValue) final override; + + HRESULT __stdcall get_HostRawElementProvider( + _COM_Outptr_opt_result_maybenull_ ::IRawElementProviderSimple** hostRawElementProviderSimple) final override; + +private: + ::ProviderOptions m_providerOptions{ ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading }; + std::wstring m_name{ L"" }; + bool m_isContent{ true }; + bool m_isControl{ true }; + long m_uiaControlTypeId{ UIA_CustomControlTypeId }; + winrt::com_ptr<::IRawElementProviderSimple> m_hostProvider{ nullptr }; +}; + +} \ No newline at end of file diff --git a/LottieIsland/AutomationFragment.cpp b/LottieIsland/AutomationFragment.cpp new file mode 100644 index 00000000..f98a5b2d --- /dev/null +++ b/LottieIsland/AutomationFragment.cpp @@ -0,0 +1,294 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "AutomationFragment.h" +#include + +using unique_safearray = wil::unique_any; + +namespace AutomationHelpers +{ + +std::unique_ptr AutomationFragment::SetFragmentCallbackHandler( + IAutomationFragmentCallbackHandler* const handler) +{ + AddHandler(AutomationCallbackHandlerType::Fragment, handler); + return AutomationCallbackRevoker::Create(GetWeak(), handler); +} + +void AutomationFragment::AddChildToEnd( + winrt::com_ptr const& child) +{ + std::unique_lock lock{ m_mutex }; + + if (nullptr == child) + { + // Nothing to do. + return; + } + + // The child should not already have a parent. + winrt::check_bool(nullptr == child->Parent()); + + // Set us up as the parent for the new child. + child->Parent(GetWeak()); + + // Set up the sibling relationships. + if (!m_children.empty()) + { + auto& previousSiblingForNewChild = m_children.back(); + previousSiblingForNewChild->NextSibling(child); + child->PreviousSibling(previousSiblingForNewChild); + } + + // Finally add the child. + m_children.push_back(child); +} + +void AutomationFragment::RemoveChild( + winrt::com_ptr const& child) +{ + std::unique_lock lock{ m_mutex }; + + if (nullptr == child) + { + // Nothing to do. + return; + } + + auto iterator = std::find_if( + m_children.begin(), m_children.end(), [&child](auto const& childEntry) + { + // See if we find a matching child entry in our children. + return (childEntry.as<::IUnknown>().get() == child.as<::IUnknown>().get()); + }); + + // We cannot remove a child that isn't ours. + winrt::check_bool(m_children.end() != iterator); + + // Remove us from the parent relationship with the child. + child->Parent(nullptr); + + // Reset the sibling relationships. + auto previousSibling = child->PreviousSibling(); + auto nextSibling = child->NextSibling(); + if (nullptr != previousSibling) + { + previousSibling->NextSibling(nextSibling); + } + if (nullptr != nextSibling) + { + nextSibling->PreviousSibling(previousSibling); + } + child->PreviousSibling(nullptr); + child->NextSibling(nullptr); + + // Finally, remove the child. + m_children.erase(iterator); +} + +void AutomationFragment::RemoveAllChildren() +{ + std::unique_lock lock{ m_mutex }; + + for (auto& child : m_children) + { + // Disconnect the relationships from all our children. + child->Parent(nullptr); + child->PreviousSibling(nullptr); + child->NextSibling(nullptr); + } + + // Remove all the children. + m_children.clear(); +} + +HRESULT __stdcall AutomationFragment::Navigate( + _In_ NavigateDirection direction, + _COM_Outptr_opt_result_maybenull_ IRawElementProviderFragment** fragment) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != fragment) + { + *fragment = nullptr; + switch (direction) + { + case NavigateDirection_Parent: + { + if (auto strongParent = LockWeak(m_parent)) + { + strongParent.as().copy_to(fragment); + } + break; + } + case NavigateDirection_NextSibling: + { + if (auto strongSibling = LockWeak(m_nextSibling)) + { + strongSibling.as().copy_to(fragment); + } + break; + } + case NavigateDirection_PreviousSibling: + { + if (auto strongSibling = LockWeak(m_previousSibling)) + { + strongSibling.as().copy_to(fragment); + } + break; + } + case NavigateDirection_FirstChild: + { + if (!m_children.empty()) + { + m_children.front().as().copy_to(fragment); + } + break; + } + case NavigateDirection_LastChild: + { + if (!m_children.empty()) + { + m_children.back().as().copy_to(fragment); + } + break; + } + } + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +HRESULT __stdcall AutomationFragment::GetRuntimeId( + _Outptr_opt_result_maybenull_ SAFEARRAY** runtimeId) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != runtimeId) + { + *runtimeId = nullptr; + + unsigned long arraySizeAsUnsignedLong = static_cast(m_runtimeId.size()); + + unique_safearray runtimeIdArray{ ::SafeArrayCreateVector(VT_I4, 0, arraySizeAsUnsignedLong) }; + SAFEARRAY* rawPointerToSafeArray = runtimeIdArray.get(); + winrt::check_pointer(rawPointerToSafeArray); + + for (long i = 0; i < static_cast(arraySizeAsUnsignedLong); ++i) + { + winrt::check_hresult(::SafeArrayPutElement(rawPointerToSafeArray, &i, &(m_runtimeId[i]))); + } + + *runtimeId = runtimeIdArray.release(); + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +HRESULT __stdcall AutomationFragment::get_BoundingRectangle( + _Out_ UiaRect* boundingRectangle) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != boundingRectangle) + { + *boundingRectangle = { 0, 0, 0, 0 }; + if (auto handler = GetHandler(AutomationCallbackHandlerType::Fragment)) + { + auto screenRectangle = + handler->GetBoundingRectangleInScreenSpaceForAutomation(GetIUnknown()); + + boundingRectangle->left = screenRectangle.X; + boundingRectangle->top = screenRectangle.Y; + boundingRectangle->width = screenRectangle.Width; + boundingRectangle->height = screenRectangle.Height; + } + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +HRESULT __stdcall AutomationFragment::GetEmbeddedFragmentRoots( + _Outptr_opt_result_maybenull_ SAFEARRAY** embeddedFragmentRoots) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != embeddedFragmentRoots) + { + *embeddedFragmentRoots = nullptr; + + if (!m_embeddedFragments.empty()) + { + unsigned long vectorSizeAsUnsignedLong = static_cast(m_embeddedFragments.size()); + + unique_safearray embeddedFragmentRootsArray{ ::SafeArrayCreateVector(VT_UNKNOWN, 0, vectorSizeAsUnsignedLong) }; + SAFEARRAY* rawPointerToSafeArray = embeddedFragmentRootsArray.get(); + winrt::check_pointer(rawPointerToSafeArray); + + for (long i = 0; i < static_cast(vectorSizeAsUnsignedLong); ++i) + { + winrt::check_hresult(::SafeArrayPutElement(rawPointerToSafeArray, &i, m_embeddedFragments.at(i).as<::IUnknown>().get())); + } + + *embeddedFragmentRoots = embeddedFragmentRootsArray.release(); + } + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +HRESULT __stdcall AutomationFragment::SetFocus() +{ + try + { + std::unique_lock lock{ m_mutex }; + if (auto handler = GetHandler(AutomationCallbackHandlerType::Fragment)) + { + handler->HandleSetFocusForAutomation(GetIUnknown()); + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +HRESULT __stdcall AutomationFragment::get_FragmentRoot( + _COM_Outptr_opt_result_maybenull_ IRawElementProviderFragmentRoot** fragmentRoot) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != fragmentRoot) + { + *fragmentRoot = nullptr; + + // Walk up our fragment tree until we find our fragment root. + auto fragmentRootCandidate = GetStrong(); + bool currentCandidateIsThisObject = true; + while (nullptr != fragmentRootCandidate && nullptr == fragmentRootCandidate.try_as()) + { + // Haven't found the fragment root yet, keep walking up our tree. + fragmentRootCandidate = currentCandidateIsThisObject ? LockWeak(m_parent) : fragmentRootCandidate->Parent(); + currentCandidateIsThisObject = false; + } + + if (nullptr != fragmentRootCandidate) + { + // Found the fragment root, return it. + fragmentRootCandidate.as().copy_to(fragmentRoot); + } + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +} \ No newline at end of file diff --git a/LottieIsland/AutomationFragment.h b/LottieIsland/AutomationFragment.h new file mode 100644 index 00000000..817ebb5e --- /dev/null +++ b/LottieIsland/AutomationFragment.h @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "AutomationElement.h" +#include "AutomationCallbackRevoker.h" + +namespace AutomationHelpers +{ + +struct AutomationFragment : winrt::implements +{ + // Automation callback handler. + [[nodiscard]] std::unique_ptr SetFragmentCallbackHandler( + IAutomationFragmentCallbackHandler* const handler); + + // Methods. + void AddChildToEnd( + winrt::com_ptr const& child); + + void RemoveChild( + winrt::com_ptr const& child); + + void RemoveAllChildren(); + + // IRawElementProviderFragment implementation. + HRESULT __stdcall Navigate( + _In_ NavigateDirection direction, + _COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragment** fragment) final override; + + HRESULT __stdcall GetRuntimeId( + _Outptr_opt_result_maybenull_ SAFEARRAY** runtimeId) final override; + + HRESULT __stdcall get_BoundingRectangle( + _Out_ UiaRect* boundingRectangle) final override; + + HRESULT __stdcall GetEmbeddedFragmentRoots( + _Outptr_opt_result_maybenull_ SAFEARRAY** embeddedFragmentRoots) final override; + + HRESULT __stdcall SetFocus() final override; + + HRESULT __stdcall get_FragmentRoot( + _COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragmentRoot** fragmentRoot) final override; + +private: + // Property setters. + void Parent(winrt::weak_ref const& parent) { std::unique_lock lock{ m_mutex }; m_parent = parent; } + void PreviousSibling(winrt::weak_ref const& previousSibling) { std::unique_lock lock{ m_mutex }; m_previousSibling = previousSibling; } + void NextSibling(winrt::weak_ref const& nextSibling) { std::unique_lock lock{ m_mutex }; m_nextSibling = nextSibling; } + + // Property getters. + winrt::com_ptr Parent() const { std::unique_lock lock{ m_mutex }; return LockWeak(m_parent); } + winrt::com_ptr PreviousSibling() const { std::unique_lock lock{ m_mutex }; return LockWeak(m_previousSibling); } + winrt::com_ptr NextSibling() const { std::unique_lock lock{ m_mutex }; return LockWeak(m_nextSibling); } + int* RuntimeId() { std::unique_lock lock{ m_mutex }; return reinterpret_cast(&(m_runtimeId[0])); } + int RuntimeIdSize() const { std::unique_lock lock{ m_mutex }; return static_cast(m_runtimeId.size()); } + + // Automatically generate unique runtime IDs per fragment. + inline static unsigned __int32 s_nextAvailableInternalRuntimeId{ 0 }; + std::array m_runtimeId{ UiaAppendRuntimeId, ++s_nextAvailableInternalRuntimeId }; + + winrt::weak_ref m_parent{ nullptr }; + winrt::weak_ref m_previousSibling{ nullptr }; + winrt::weak_ref m_nextSibling{ nullptr }; + std::vector> m_children{}; + std::vector> m_embeddedFragments{}; +}; + +} \ No newline at end of file diff --git a/LottieIsland/AutomationFragmentRoot.cpp b/LottieIsland/AutomationFragmentRoot.cpp new file mode 100644 index 00000000..13c9005d --- /dev/null +++ b/LottieIsland/AutomationFragmentRoot.cpp @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "AutomationFragmentRoot.h" + +namespace AutomationHelpers +{ + +std::unique_ptr AutomationFragmentRoot::SetFragmentRootCallbackHandler( + IAutomationFragmentRootCallbackHandler* const handler) +{ + AddHandler(AutomationCallbackHandlerType::FragmentRoot, handler); + return AutomationCallbackRevoker::Create(GetWeak(), handler); +} + +HRESULT __stdcall AutomationFragmentRoot::ElementProviderFromPoint( + _In_ double x, + _In_ double y, + _COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragment** fragment) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != fragment) + { + *fragment = nullptr; + if (auto handler = GetHandler(AutomationCallbackHandlerType::FragmentRoot)) + { + handler->GetFragmentFromPointForAutomation(x, y, GetIUnknown()).copy_to(fragment); + } + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +HRESULT __stdcall AutomationFragmentRoot::GetFocus( + _COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragment** fragmentInFocus) +{ + try + { + std::unique_lock lock{ m_mutex }; + if (nullptr != fragmentInFocus) + { + *fragmentInFocus = nullptr; + if (auto handler = GetHandler(AutomationCallbackHandlerType::FragmentRoot)) + { + handler->GetFragmentInFocusForAutomation(GetIUnknown()).copy_to(fragmentInFocus); + } + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +} \ No newline at end of file diff --git a/LottieIsland/AutomationFragmentRoot.h b/LottieIsland/AutomationFragmentRoot.h new file mode 100644 index 00000000..15ee6a1d --- /dev/null +++ b/LottieIsland/AutomationFragmentRoot.h @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "AutomationFragment.h" + +namespace AutomationHelpers +{ + +struct AutomationFragmentRoot : winrt::implements +{ + // Automation callback handler. + [[nodiscard]] std::unique_ptr SetFragmentRootCallbackHandler( + IAutomationFragmentRootCallbackHandler* const handler); + + // IRawElementProviderFragmentRoot implementation. + HRESULT __stdcall ElementProviderFromPoint( + _In_ double x, + _In_ double y, + _COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragment** fragment) final override; + + HRESULT __stdcall GetFocus( + _COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragment** fragmentInFocus) final override; +}; + +} \ No newline at end of file diff --git a/LottieIsland/CommunityToolkit.WinAppSDK.LottieIsland.def b/LottieIsland/CommunityToolkit.WinAppSDK.LottieIsland.def new file mode 100644 index 00000000..24e7c123 --- /dev/null +++ b/LottieIsland/CommunityToolkit.WinAppSDK.LottieIsland.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/LottieIsland/CommunityToolkit.WinAppSDK.LottieIsland.idl b/LottieIsland/CommunityToolkit.WinAppSDK.LottieIsland.idl new file mode 100644 index 00000000..495050df --- /dev/null +++ b/LottieIsland/CommunityToolkit.WinAppSDK.LottieIsland.idl @@ -0,0 +1,45 @@ +namespace CommunityToolkit.WinAppSDK.LottieIsland +{ + interface IAnimatedVisualFrameworkless + requires Windows.Foundation.IClosable + { + Windows.Foundation.TimeSpan Duration{ get; }; + Microsoft.UI.Composition.Visual RootVisual{ get; }; + Windows.Foundation.Numerics.Vector2 Size{ get; }; + }; + + runtimeclass LottieContentIsland + { + static LottieContentIsland Create(Microsoft.UI.Composition.Compositor compositor); + + IAnimatedVisualFrameworkless AnimatedVisual; + + Windows.Foundation.TimeSpan Duration{ get; }; + + Boolean IsAnimationLoaded{ get; }; + + Microsoft.UI.Content.ContentIsland Island{ get; }; + + Boolean IsPlaying{ get; }; + + Windows.Foundation.IAsyncAction PlayAsync(Single fromProgress, Single toProgress, Boolean looped); + + Single PlaybackRate; + + void Pause(); + + void Resume(); + + void Stop(); + + event Windows.Foundation.TypedEventHandler PointerEntered; + + event Windows.Foundation.TypedEventHandler PointerExited; + + event Windows.Foundation.TypedEventHandler PointerMoved; + + event Windows.Foundation.TypedEventHandler PointerPressed; + + event Windows.Foundation.TypedEventHandler PointerReleased; + } +} diff --git a/LottieIsland/Directory.Build.props b/LottieIsland/Directory.Build.props new file mode 100644 index 00000000..22b90cca --- /dev/null +++ b/LottieIsland/Directory.Build.props @@ -0,0 +1,7 @@ + + + $([MSBuild]::NormalizeDirectory('$(SolutionDir)', '_build', '$(Platform)', '$(Configuration)')) + $([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'bin')) + $([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'obj')) + + \ No newline at end of file diff --git a/LottieIsland/LottieContentIsland.cpp b/LottieIsland/LottieContentIsland.cpp new file mode 100644 index 00000000..a0fc5082 --- /dev/null +++ b/LottieIsland/LottieContentIsland.cpp @@ -0,0 +1,347 @@ +#include "pch.h" +#include "LottieContentIsland.h" +#include "LottieContentIsland.g.cpp" + +namespace winrt::CommunityToolkit::WinAppSDK::LottieIsland::implementation +{ + winrt::LottieContentIsland LottieContentIsland::Create(const winrt::Compositor& compositor) + { + return winrt::make(compositor); + } + + LottieContentIsland::LottieContentIsland( + const winrt::Compositor& compositor) + : m_compositor(compositor) + { + m_rootVisual = m_compositor.CreateContainerVisual(); + m_island = winrt::ContentIsland::Create(m_rootVisual); + m_island.AppData(get_strong().as()); + + m_island.AutomationProviderRequested({ get_weak(), &LottieContentIsland::OnIslandAutomationProviderRequested }); + m_island.StateChanged({ get_weak(), &LottieContentIsland::OnIslandStateChanged }); + + // Once it's not experimental, we should use InputPointerSource::GetForVisual on our root visual. + // This will give us automatic hittesting for whatever content and shape the Lottie animation has. + // Currently hittesting will just be a rectangle the size of the island, regardless of content. + m_inputPointerSource = winrt::Microsoft::UI::Input::InputPointerSource::GetForIsland(m_island); + + InitializeInputHandlers(); + } + + LottieContentIsland::~LottieContentIsland() + { + // Dispose (Close) our island. This will revoke any event handlers from it or sub-objects, which + // is why the LottieContentIsland doesn't need to manually revoke event handlers. + m_island.Close(); + } + + winrt::IAnimatedVisualFrameworkless LottieContentIsland::AnimatedVisual() const + { + // Return the AnimatedVisualSource + return m_animatedVisual; + } + + void LottieContentIsland::AnimatedVisual(winrt::IAnimatedVisualFrameworkless const& value) + { + if (m_animatedVisual == value) + { + return; + } + + if (m_animatedVisual != nullptr) + { + StopAnimation(); + m_rootVisual.Children().RemoveAll(); + m_animatedVisual = nullptr; + } + + if (value != nullptr) + { + // Set the AnimatedVisualSource + m_animatedVisual = value; + + // Set up lottie + winrt::Visual lottieVisual = m_animatedVisual.RootVisual(); + m_rootVisual.Children().InsertAtTop(lottieVisual); + + // Tell our hosting environment that our size changed, and ask for confirmation of our ActualSize. + // Any changes will come back through a StateChanged notification + m_island.RequestSize(m_animatedVisual.Size()); + + // While that request is propagating, resize ourselves to fill the island's current size + Resize(m_island.ActualSize()); + + StartAnimation(0.0, 1.0, true /*loop*/); + } + } + + winrt::Windows::Foundation::TimeSpan LottieContentIsland::Duration() const + { + if (m_animatedVisual == nullptr) + { + return 0ms; + } + + return m_animatedVisual.Duration(); + } + + bool LottieContentIsland::IsAnimationLoaded() const + { + // Revisit this when we get JSON loading to work. + return m_animatedVisual != nullptr; + } + + bool LottieContentIsland::IsPlaying() const + { + return m_progressPropertySet != nullptr; + } + + float LottieContentIsland::PlaybackRate() const + { + return m_playbackRate; + } + + void LottieContentIsland::PlaybackRate(float rate) + { + m_playbackRate = rate; + if (m_animationController != nullptr) + { + m_animationController.PlaybackRate(m_playbackRate); + } + } + + void LottieContentIsland::Pause() + { + if (m_animationController != nullptr) + { + m_animationController.Pause(); + } + } + + winrt::Windows::Foundation::IAsyncAction LottieContentIsland::PlayAsync(float fromProgress, float toProgress, bool looped) + { + if (m_animationCompletionEvent.get() == nullptr) + { + m_animationCompletionEvent = winrt::handle(CreateEvent(nullptr, false, false, nullptr)); + } + + // Stop any existing animation + StopAnimation(); + + auto batch = m_compositor.CreateScopedBatch(CompositionBatchTypes::Animation); + + StartAnimation(fromProgress, toProgress, looped); + + // Keep track of whether the animation is looped, since we will have to + // manually fire the event if Stop() is called in the non-looped case. + // We don't hook up the event here in the looped case, because ScopedBatches + // complete immediately if their animation is looped. + m_looped = looped; + if (!looped) + { + // Hook up an event handler to the Completed event of the batch + batch.Completed([&](auto&&, auto&&) + { + // Set the completion event when the batch completes + SetEvent(m_animationCompletionEvent.get()); + }); + } + + // Commit the batch + batch.End(); + + // Wait for the completion event asynchronously + co_await winrt::resume_on_signal(m_animationCompletionEvent.get()); // Wait for the event to be signaled + } + + void LottieContentIsland::Resume() + { + if (m_animationController != nullptr) + { + m_animationController.Resume(); + } + } + + void LottieContentIsland::Stop() + { + StopAnimation(); + } + + winrt::Windows::Graphics::RectInt32 LottieContentIsland::GetBoundingRectangleInScreenSpaceForAutomation( + ::IUnknown const* const /*sender*/) const + { + // Convert our local bounds to screen space and return it to UI Automation. + auto coordinateConverter = m_island.CoordinateConverter(); + auto actualSize = m_island.ActualSize(); + winrt::Windows::Foundation::Rect islandLocalBounds{ 0, 0, actualSize.x, actualSize.y }; + auto islandScreenBounds = coordinateConverter.ConvertLocalToScreen(islandLocalBounds); + return islandScreenBounds; + } + + void LottieContentIsland::HandleSetFocusForAutomation( + ::IUnknown const* const /*sender*/) + { + // No-op. + } + + winrt::com_ptr<::IRawElementProviderFragment> LottieContentIsland::GetFragmentFromPointForAutomation( + double /*x*/, + double /*y*/, + ::IUnknown const* const /*sender*/) const + { + // No child automation fragments. + return nullptr; + } + + winrt::com_ptr<::IRawElementProviderFragment> LottieContentIsland::GetFragmentInFocusForAutomation( + ::IUnknown const* const /*sender*/) const + { + // No child automation fragments. + return nullptr; + } + + void LottieContentIsland::HandleInvokeForAutomation( + ::IUnknown const* const /*sender*/) + { + if (nullptr != m_animatedVisual) + { + IsPlaying() ? StopAnimation() : StartAnimation(0.0f, 1.0f, false); + } + } + + void LottieContentIsland::StartAnimation(float fromProgress, float toProgress, bool loop) + { + if (m_animatedVisual == nullptr) + { + throw winrt::hresult_illegal_method_call{ L"Cannot start an animation before the animation is loaded." }; + } + + auto animation = m_compositor.CreateScalarKeyFrameAnimation(); + animation.Duration(m_animatedVisual.Duration()); + auto linearEasing = m_compositor.CreateLinearEasingFunction(); + animation.InsertKeyFrame(0, fromProgress); + animation.InsertKeyFrame(1, toProgress, linearEasing); + if (loop) + { + animation.IterationBehavior(winrt::AnimationIterationBehavior::Forever); + } + else + { + animation.IterationBehavior(winrt::AnimationIterationBehavior::Count); + animation.IterationCount(1); + } + + m_progressPropertySet = m_animatedVisual.RootVisual().Properties(); + m_progressPropertySet.StartAnimation(L"Progress", animation); + m_animationController = m_progressPropertySet.TryGetAnimationController(L"Progress"); + m_animationController.PlaybackRate(m_playbackRate); + m_previousFromProgress = fromProgress; + } + + void LottieContentIsland::StopAnimation() + { + if (!IsPlaying()) + { + // No-op + return; + } + + // Stop and snap to the beginning of the animation + m_progressPropertySet.StopAnimation(L"Progress"); + m_progressPropertySet.InsertScalar(L"Progress", m_previousFromProgress); + + if (m_looped) + { + SetEvent(m_animationCompletionEvent.get()); + } + + // Cleanup + m_previousFromProgress = 0.0; + m_animationController = nullptr; + m_progressPropertySet = nullptr; + } + + void LottieContentIsland::OnIslandAutomationProviderRequested( + const winrt::ContentIsland& island, + const winrt::ContentIslandAutomationProviderRequestedEventArgs& args) + { + if (nullptr == m_automationProvider) + { + // We need to create the automation provider. + m_automationProvider = winrt::make_self(); + m_automationProvider->Name(L"Lottie"); + + // Register ourselves as the callback for our automation provider. + m_fragmentCallbackRevoker = m_automationProvider->SetFragmentCallbackHandler(this); + m_fragmentRootCallbackRevoker = m_automationProvider->SetFragmentRootCallbackHandler(this); + m_invokeCallbackRevoker = m_automationProvider->SetInvokeCallbackHandler(this); + + // Set up the host provider. + auto hostProviderAsIInspectable = island.GetAutomationHostProvider(); + m_automationProvider->HostProvider(hostProviderAsIInspectable.try_as<::IRawElementProviderSimple>()); + } + + args.AutomationProvider(m_automationProvider.as()); + args.Handled(true); + } + + void LottieContentIsland::OnIslandStateChanged(const winrt::ContentIsland& /*island*/, const winrt::ContentIslandStateChangedEventArgs& args) + { + if (args.DidActualSizeChange() && IsAnimationLoaded()) + { + Resize(m_island.ActualSize()); + } + } + + void LottieContentIsland::Resize(const float2& newSize) + { + float2 desiredSize = m_animatedVisual.Size(); + if (newSize.x == 0 || newSize.y == 0 || desiredSize.x == 0 || desiredSize.y == 0) + { + // Don't try to scale (and hit fun divide by 0) if we have no effective size + m_rootVisual.Size({ 0, 0 }); + } + else + { + // We implement Uniform stretching here, where we don't overflow bounds, + // but keep aspect ratio. + float2 scale = newSize / m_animatedVisual.Size(); + + // Take the smaller scale and set both axes to that. + if (scale.x < scale.y) + { + scale.y = scale.x; + } + else + { + scale.x = scale.y; + } + + m_rootVisual.Size(desiredSize); + m_rootVisual.Scale({ scale.x, scale.y, 1.f }); + } + } + + void LottieContentIsland::InitializeInputHandlers() + { + m_inputPointerSource.PointerEntered([this](auto& /*sender*/, auto& args) { + m_pointerEnteredEvent(*this, args); + }); + + m_inputPointerSource.PointerExited([this](auto& /*sender*/, auto& args) { + m_pointerExitedEvent(*this, args); + }); + + m_inputPointerSource.PointerMoved([this](auto& /*sender*/, auto& args) { + m_pointerMovedEvent(*this, args); + }); + + m_inputPointerSource.PointerPressed([this](auto& /*sender*/, auto& args) { + m_pointerPressedEvent(*this, args); + }); + + m_inputPointerSource.PointerReleased([this](auto& /*sender*/, auto& args) { + m_pointerReleasedEvent(*this, args); + }); + } +} diff --git a/LottieIsland/LottieContentIsland.h b/LottieIsland/LottieContentIsland.h new file mode 100644 index 00000000..0653c33c --- /dev/null +++ b/LottieIsland/LottieContentIsland.h @@ -0,0 +1,126 @@ +#pragma once + +#include "LottieContentIsland.g.h" +#include "winrt/CommunityToolkit.WinAppSDK.LottieIsland.h" +#include "LottieIslandAutomationProvider.h" + +namespace winrt +{ + using namespace ::winrt::CommunityToolkit::WinAppSDK::LottieIsland; +} + +namespace winrt::CommunityToolkit::WinAppSDK::LottieIsland::implementation +{ + struct LottieContentIsland : LottieContentIslandT, + AutomationHelpers::IAutomationFragmentCallbackHandler, + AutomationHelpers::IAutomationFragmentRootCallbackHandler, + AutomationHelpers::IAutomationInvokeCallbackHandler + { + using PointerEventHandler = Windows::Foundation::TypedEventHandler; + + static winrt::LottieContentIsland Create(const winrt::Compositor& compositor); + + LottieContentIsland(const winrt::Compositor& compositor); + ~LottieContentIsland(); + + winrt::ContentIsland Island() const + { + return m_island; + } + + winrt::IAnimatedVisualFrameworkless AnimatedVisual() const; + void AnimatedVisual(const winrt::IAnimatedVisualFrameworkless& source); + + winrt::Windows::Foundation::TimeSpan Duration() const; + + bool IsAnimationLoaded() const; + + bool IsPlaying() const; + + float PlaybackRate() const; + void PlaybackRate(float rate); + + winrt::event_token PointerEntered(const PointerEventHandler& handler) { return m_pointerEnteredEvent.add(handler); } + void PointerEntered(winrt::event_token const& token) noexcept { m_pointerEnteredEvent.remove(token); } + + winrt::event_token PointerExited(const PointerEventHandler& handler) { return m_pointerExitedEvent.add(handler); } + void PointerExited(winrt::event_token const& token) noexcept { m_pointerExitedEvent.remove(token); } + + winrt::event_token PointerMoved(const PointerEventHandler& handler) { return m_pointerMovedEvent.add(handler); } + void PointerMoved(winrt::event_token const& token) noexcept { m_pointerMovedEvent.remove(token); } + + winrt::event_token PointerPressed(const PointerEventHandler& handler) { return m_pointerPressedEvent.add(handler); } + void PointerPressed(winrt::event_token const& token) noexcept { m_pointerPressedEvent.remove(token); } + + winrt::event_token PointerReleased(const PointerEventHandler& handler) { return m_pointerReleasedEvent.add(handler); } + void PointerReleased(winrt::event_token const& token) noexcept { m_pointerReleasedEvent.remove(token); } + + void Pause(); + + winrt::Windows::Foundation::IAsyncAction PlayAsync(float fromProgress, float toProgress, bool looped); + + void Resume(); + + void Stop(); + + // UI Automation callback implementation. + winrt::Windows::Graphics::RectInt32 GetBoundingRectangleInScreenSpaceForAutomation( + ::IUnknown const* const sender) const final override; + + void HandleSetFocusForAutomation( + ::IUnknown const* const sender) final override; + + winrt::com_ptr<::IRawElementProviderFragment> GetFragmentFromPointForAutomation( + double x, + double y, + ::IUnknown const* const sender) const final override; + + winrt::com_ptr<::IRawElementProviderFragment> GetFragmentInFocusForAutomation( + ::IUnknown const* const sender) const final override; + + void HandleInvokeForAutomation( + ::IUnknown const* const sender) final override; + + private: + void StartAnimation(float fromProgress, float toProgress, bool loop); + void StopAnimation(); + + void OnIslandAutomationProviderRequested(const winrt::ContentIsland& island, const winrt::ContentIslandAutomationProviderRequestedEventArgs& args); + void OnIslandStateChanged(const winrt::ContentIsland& island, const winrt::ContentIslandStateChangedEventArgs& args); + + void Resize(const float2& size); + + void InitializeInputHandlers(); + + winrt::event m_pointerEnteredEvent; + winrt::event m_pointerExitedEvent; + winrt::event m_pointerMovedEvent; + winrt::event m_pointerPressedEvent; + winrt::event m_pointerReleasedEvent; + + // UI Automation. + winrt::com_ptr m_automationProvider{ nullptr }; + std::unique_ptr m_fragmentCallbackRevoker{ nullptr }; + std::unique_ptr m_fragmentRootCallbackRevoker{ nullptr }; + std::unique_ptr m_invokeCallbackRevoker{ nullptr }; + + winrt::Compositor m_compositor{ nullptr }; + winrt::ContainerVisual m_rootVisual{ nullptr }; + winrt::ContentIsland m_island{ nullptr }; + winrt::InputPointerSource m_inputPointerSource{ nullptr }; + winrt::IAnimatedVisualFrameworkless m_animatedVisual{ nullptr }; + winrt::CompositionPropertySet m_progressPropertySet{ nullptr }; + winrt::AnimationController m_animationController{ nullptr }; + float m_previousFromProgress = 0.0; + float m_playbackRate = 1.0f; + winrt::handle m_animationCompletionEvent{ nullptr }; + bool m_looped; + }; +} + +namespace winrt::CommunityToolkit::WinAppSDK::LottieIsland::factory_implementation +{ + struct LottieContentIsland : LottieContentIslandT + { + }; +} diff --git a/LottieIsland/LottieIsland.vcxproj b/LottieIsland/LottieIsland.vcxproj new file mode 100644 index 00000000..bc881453 --- /dev/null +++ b/LottieIsland/LottieIsland.vcxproj @@ -0,0 +1,180 @@ + + + + + + + true + true + true + {9ba7a2f2-b723-458b-a575-3f726d271465} + LottieIsland + CommunityToolkit.WinAppSDK.LottieIsland + CommunityToolkit.WinAppSDK.LottieIsland + + 0.2.7-prerelease + en-US + 14.0 + Windows Store + 10.0 + 10.0.19041.0 + 10.0.17134.0 + None + Win32Proj + + + + + Debug + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + DynamicLibrary + v143 + Unicode + false + + + true + true + + + false + true + false + + + + + + + + + + + + + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + %(AdditionalOptions) /bigobj + _WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + false + CommunityToolkit.WinAppSDK.LottieIsland.def + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + true + true + + + + + + + + + + + + + CommunityToolkit.WinAppSDK.LottieIsland.idl + + + + + + + + + + Create + + + CommunityToolkit.WinAppSDK.LottieIsland.idl + + + + + + + + + + + + + + + false + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + \ No newline at end of file diff --git a/LottieIsland/LottieIsland.vcxproj.filters b/LottieIsland/LottieIsland.vcxproj.filters new file mode 100644 index 00000000..fe286ca2 --- /dev/null +++ b/LottieIsland/LottieIsland.vcxproj.filters @@ -0,0 +1,74 @@ + + + + + accd3aa8-1ba0-4223-9bbe-0c431709210b + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + {926ab91d-31b4-48c3-b9a4-e681349f27f0} + + + {8de2e0c6-cc70-4b56-a68f-dd3ec76ce5fc} + + + {f244735f-9786-4673-9823-f1b890d98b19} + + + + + + + Automation + + + Automation + + + Automation + + + Automation + + + + + + + Automation + + + Automation + + + Automation + + + Automation + + + Automation + + + Automation + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LottieIsland/LottieIslandAutomationProvider.cpp b/LottieIsland/LottieIslandAutomationProvider.cpp new file mode 100644 index 00000000..7a05f90d --- /dev/null +++ b/LottieIsland/LottieIslandAutomationProvider.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "LottieIslandAutomationProvider.h" + +namespace LottieIslandInternal +{ + + +std::unique_ptr LottieIslandAutomationProvider::SetInvokeCallbackHandler( + AutomationHelpers::IAutomationInvokeCallbackHandler* const handler) +{ + AddHandler(AutomationHelpers::AutomationCallbackHandlerType::Invoke, handler); + return AutomationHelpers::AutomationCallbackRevoker::Create(GetWeak(), handler); +} + + +HRESULT __stdcall LottieIslandAutomationProvider::Invoke() +{ + try + { + std::unique_lock lock{ m_mutex }; + if (auto handler = GetHandler( + AutomationHelpers::AutomationCallbackHandlerType::Invoke)) + { + handler->HandleInvokeForAutomation(GetIUnknown()); + } + } + catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; } + return S_OK; +} + +} \ No newline at end of file diff --git a/LottieIsland/LottieIslandAutomationProvider.h b/LottieIsland/LottieIslandAutomationProvider.h new file mode 100644 index 00000000..5b50952c --- /dev/null +++ b/LottieIsland/LottieIslandAutomationProvider.h @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "AutomationFragmentRoot.h" + +namespace LottieIslandInternal +{ + +struct LottieIslandAutomationProvider : winrt::implements +{ + // Automation callback handler. + [[nodiscard]] std::unique_ptr SetInvokeCallbackHandler( + AutomationHelpers::IAutomationInvokeCallbackHandler* const handler); + + // IInvokeProvider implementation. + HRESULT __stdcall Invoke() final override; +}; + +} \ No newline at end of file diff --git a/LottieIsland/PropertySheet.props b/LottieIsland/PropertySheet.props new file mode 100644 index 00000000..e34141b0 --- /dev/null +++ b/LottieIsland/PropertySheet.props @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/LottieIsland/packages.config b/LottieIsland/packages.config new file mode 100644 index 00000000..c4397c32 --- /dev/null +++ b/LottieIsland/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/LottieIsland/pch.cpp b/LottieIsland/pch.cpp new file mode 100644 index 00000000..bcb5590b --- /dev/null +++ b/LottieIsland/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/LottieIsland/pch.h b/LottieIsland/pch.h new file mode 100644 index 00000000..8b532686 --- /dev/null +++ b/LottieIsland/pch.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include + +// Xaml has a GetCurrentTime, and somewhere in the windows sdk there's a macro for it. +// These conflict and cause issues. +#undef GetCurrentTime + +#include +#include +#include +#include +#include +#include +#include + +namespace winrt +{ + using namespace ::winrt::Microsoft::UI::Composition; + using namespace ::winrt::Microsoft::UI::Content; + using namespace ::winrt::Microsoft::UI::Input; +} + +// Opt into time literals (i.e. 200ms, 1min, 15s) +using namespace std::chrono_literals; + +using float2 = winrt::Windows::Foundation::Numerics::float2; diff --git a/LottieIslandProjection/Directory.Build.props b/LottieIslandProjection/Directory.Build.props new file mode 100644 index 00000000..22b90cca --- /dev/null +++ b/LottieIslandProjection/Directory.Build.props @@ -0,0 +1,7 @@ + + + $([MSBuild]::NormalizeDirectory('$(SolutionDir)', '_build', '$(Platform)', '$(Configuration)')) + $([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'bin')) + $([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'obj')) + + \ No newline at end of file diff --git a/LottieIslandProjection/LottieIslandProjection.csproj b/LottieIslandProjection/LottieIslandProjection.csproj new file mode 100644 index 00000000..14ddd1bb --- /dev/null +++ b/LottieIslandProjection/LottieIslandProjection.csproj @@ -0,0 +1,31 @@ + + + + LottieIslandProjection + net7.0-windows10.0.19041.0 + CommunityToolkit.WinAppSDK.LottieIsland + + 0.2.7-prerelease + + Any CPU + + + CommunityToolkit.WinAppSDK.LottieIsland.Projection + $(MSBuildThisFileDirectory)..\bin\nupkg\ + True + nuget\CommunityToolkit.WinAppSDK.LottieIsland.nuspec + + + CommunityToolkit.WinAppSDK.LottieIsland + $(OutDir) + None + + + + + + + + + + diff --git a/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-WinUI3.targets b/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-WinUI3.targets new file mode 100644 index 00000000..b3495602 --- /dev/null +++ b/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-WinUI3.targets @@ -0,0 +1,27 @@ + + + + + x64 + x86 + + + + x86 + $(Platform) + + + + + true + + + + + + + + + + + diff --git a/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-managed.targets b/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-managed.targets new file mode 100644 index 00000000..f80afb25 --- /dev/null +++ b/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-managed.targets @@ -0,0 +1,31 @@ + + + + + x64 + x86 + + + + x86 + $(Platform) + + + + + true + + + + + $(MSBuildThisFileDirectory)..\..\lib\uap10.0\CommunityToolkit.WinAppSDK.LottieIsland.winmd + CommunityToolkit.WinAppSDK.LottieIsland.dll + + + + + + + + + diff --git a/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-native.targets b/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-native.targets new file mode 100644 index 00000000..c26e7ef5 --- /dev/null +++ b/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-native.targets @@ -0,0 +1,25 @@ + + + + + x86 + $(Platform) + + + + + CommunityToolkit.WinAppSDK.LottieIsland.dll + + + + + + + + $(MSBuildThisFileDirectory)..\..\Include; + $(MSBuildThisFileDirectory)..\..\Include\$(lottieisland-Platform); + %(AdditionalIncludeDirectories); + + + + diff --git a/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-win10.targets b/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-win10.targets new file mode 100644 index 00000000..671e0291 --- /dev/null +++ b/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland-win10.targets @@ -0,0 +1,4 @@ + + + + diff --git a/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland.nuspec b/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland.nuspec new file mode 100644 index 00000000..4bdb0a9d --- /dev/null +++ b/LottieIslandProjection/nuget/CommunityToolkit.WinAppSDK.LottieIsland.nuspec @@ -0,0 +1,44 @@ + + + + CommunityToolkit.WinAppSDK.LottieIsland + Microsoft + + 0.2.7-prerelease + A ContentIsland to host Lottie Animations + images\icon.png + docs\readme.md + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LottieIslandProjection/nuget/icon.png b/LottieIslandProjection/nuget/icon.png new file mode 100644 index 00000000..5cae1f76 Binary files /dev/null and b/LottieIslandProjection/nuget/icon.png differ diff --git a/LottieIslandProjection/nuget/readme.md b/LottieIslandProjection/nuget/readme.md new file mode 100644 index 00000000..6ff4aa2b --- /dev/null +++ b/LottieIslandProjection/nuget/readme.md @@ -0,0 +1,7 @@ +# LottieIsland + +This project shows a sample ContentIsland that hosts a Lottie animation. + +For more information on Lottie animations, check out [Lottie-Windows](https://github.com/CommunityToolkit/Lottie-Windows) on GitHub! + +To generate a nuget package, pack the LottieIslandProjection project using Visual Studio. Make sure you have built LottieIsland for x86, x64, and ARM64 Release, and built/pack LottieIslandProjection for Release|AnyCPU. \ No newline at end of file diff --git a/LottieWinRT/LottieVisualSourceWinRT.cs b/LottieWinRT/LottieVisualSourceWinRT.cs new file mode 100644 index 00000000..c13e9a9a --- /dev/null +++ b/LottieWinRT/LottieVisualSourceWinRT.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using CommunityToolkit.WinAppSDK.LottieIsland; +using CommunityToolkit.WinUI.Lottie; +using Microsoft.UI.Composition; +using LottieIsland = CommunityToolkit.WinAppSDK.LottieIsland; + +namespace CommunityToolkit.WinAppSDK.LottieWinRT +{ + public sealed class LottieVisualSourceWinRT + { + public event EventHandler? AnimatedVisualInvalidated; + + private LottieVisualSource _lottieVisualSource; + + public LottieVisualSourceWinRT() + { + _lottieVisualSource = new LottieVisualSource(); + } + + private LottieVisualSourceWinRT(LottieVisualSource lottieVisualSource) + { + _lottieVisualSource = lottieVisualSource; + _lottieVisualSource.AnimatedVisualInvalidated += (LottieVisualSource? sender, object? o) => + { + AnimatedVisualInvalidated?.Invoke(this, o); + }; + } + + public static LottieVisualSourceWinRT? CreateFromString(string uri) + { + LottieVisualSource? lottieSource = LottieVisualSource.CreateFromString(uri); + if (lottieSource == null) + { + return null; + } + + LottieVisualSourceWinRT winrtSource = new LottieVisualSourceWinRT(lottieSource); + + return winrtSource; + } + + /// + /// Gets or sets the Uniform Resource Identifier (URI) of the JSON source file for this . + /// + public Uri? UriSource + { + get => _lottieVisualSource?.UriSource; + set + { + if (_lottieVisualSource != null) + { + _lottieVisualSource.UriSource = value; + } + } + } + + /// + /// Implements . + /// WinRT Wrapper around for use by C++ or non-WinUI applications. + /// + /// The that can be used as a factory for the resulting . + /// An optional object that may provide extra information about the result. + /// An . + public LottieIsland.IAnimatedVisualFrameworkless? TryCreateAnimatedVisual( + Compositor compositor, + out object? diagnostics) + { + diagnostics = null; + return _lottieVisualSource?.TryCreateAnimatedVisual(compositor, out diagnostics); + } + } +} diff --git a/LottieWinRT/LottieWinRT.csproj b/LottieWinRT/LottieWinRT.csproj new file mode 100644 index 00000000..fc4dbd9c --- /dev/null +++ b/LottieWinRT/LottieWinRT.csproj @@ -0,0 +1,50 @@ + + + + net7.0-windows10.0.19041.0 + true + enable + x64;x86;ARM64 + true + CommunityToolkit.WinAppSDK.LottieWinRT + CommunityToolkit.WinAppSDK.LottieWinRT + win-x86;win-x64;win-arm64 + 10.0.19041.0 + + true + true + + None + + + + + + + + + + + + + + + $(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage + + + + + + + + + + + + + + + + + + diff --git a/SimpleLottieIslandApp/Assets/LottieLogo1.json b/SimpleLottieIslandApp/Assets/LottieLogo1.json new file mode 100644 index 00000000..cb637e3e --- /dev/null +++ b/SimpleLottieIslandApp/Assets/LottieLogo1.json @@ -0,0 +1,7390 @@ +{ + "assets": [], + "layers": [ + { + "ddd": 0, + "ind": 0, + "ty": 1, + "nm": "MASTER", + "ks": { + "o": { "k": 0 }, + "r": { "k": 0 }, + "p": { "k": [ 214.457, 347.822, 0 ] }, + "a": { "k": [ 60, 60, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "sw": 120, + "sh": 120, + "sc": "#ffffff", + "ip": 12, + "op": 179, + "st": 0, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 1, + "ty": 4, + "nm": "S5-Y 4", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": -89.1 }, + "p": { "k": [ 53.205, 131.606, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 142.038, 29.278 ], + [ 131.282, 21.807 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 76, + "s": [ 87 ], + "e": [ 50.633 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 79, + "s": [ 50.633 ], + "e": [ 0 ] + }, + { "t": 83 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 76, + "s": [ 100 ], + "e": [ 75.856 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 79, + "s": [ 75.856 ], + "e": [ 0 ] + }, + { "t": 83 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 76, + "op": 84, + "st": 40, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 2, + "ty": 4, + "nm": "S4-Y 4", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": -89.1 }, + "p": { "k": [ 53.205, 131.606, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 142.183, -5.112 ], + [ 130.029, 5.016 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 76, + "s": [ 87 ], + "e": [ 43.833 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 79, + "s": [ 43.833 ], + "e": [ 0 ] + }, + { "t": 83 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 76, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 79, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 83 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 76, + "op": 84, + "st": 40, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 3, + "ty": 4, + "nm": "S3-Y 4", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": -89.1 }, + "p": { "k": [ 53.205, 131.606, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 147.699, 13.025 ], + [ 133.195, 13.21 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 76, + "s": [ 87 ], + "e": [ 42.133 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 79, + "s": [ 42.133 ], + "e": [ 0 ] + }, + { "t": 83 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 76, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 79, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 83 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 76, + "op": 84, + "st": 40, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 4, + "ty": 4, + "nm": "S5-Y 3", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 97.9 }, + "p": { "k": [ 58.205, -39.394, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 145.677, 22.22 ], + [ 134.922, 14.749 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 75, + "s": [ 87 ], + "e": [ 50.633 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 78, + "s": [ 50.633 ], + "e": [ 0 ] + }, + { "t": 82 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 75, + "s": [ 100 ], + "e": [ 75.856 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 78, + "s": [ 75.856 ], + "e": [ 0 ] + }, + { "t": 82 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 75, + "op": 83, + "st": 39, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 5, + "ty": 4, + "nm": "S4-Y 3", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 97.9 }, + "p": { "k": [ 58.205, -39.394, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 144.429, -5.397 ], + [ 132.275, 4.731 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 75, + "s": [ 87 ], + "e": [ 43.833 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 78, + "s": [ 43.833 ], + "e": [ 0 ] + }, + { "t": 82 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 75, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 78, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 82 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 75, + "op": 83, + "st": 39, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 6, + "ty": 4, + "nm": "S3-Y 3", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 97.9 }, + "p": { "k": [ 58.205, -39.394, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 149.624, 8.244 ], + [ 136.648, 10.156 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 75, + "s": [ 87 ], + "e": [ 42.133 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 78, + "s": [ 42.133 ], + "e": [ 0 ] + }, + { "t": 82 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 75, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 78, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 82 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 75, + "op": 83, + "st": 39, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 7, + "ty": 4, + "nm": "S13", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 128, 3.65 ], + [ 78.25, 3.5 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 85, + "s": [ 87 ], + "e": [ 21.233 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 90, + "s": [ 21.233 ], + "e": [ 0 ] + }, + { "t": 94 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 85, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 90, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 94 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 1.5 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 85, + "op": 95, + "st": 49, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 8, + "ty": 4, + "nm": "S12", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 119.25, -20.05 ], + [ 63.5, -20.5 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 84, + "s": [ 87 ], + "e": [ 21.233 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 87, + "s": [ 21.233 ], + "e": [ 0 ] + }, + { "t": 91 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 84, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 87, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 91 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 1.5 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 84, + "op": 94, + "st": 48, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 9, + "ty": 4, + "nm": "S11", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 119.5, -45.05 ], + [ 82.75, -44.75 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 80, + "s": [ 87 ], + "e": [ 21.233 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 83, + "s": [ 21.233 ], + "e": [ 0 ] + }, + { "t": 87 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 80, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 83, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 87 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 1.5 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 80, + "op": 90, + "st": 44, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 10, + "ty": 4, + "nm": "S5-Y 2", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 169.5, 18.073 ], + [ 137.481, 11.365 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 97, + "s": [ 87 ], + "e": [ 50.633 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 100, + "s": [ 50.633 ], + "e": [ 0 ] + }, + { "t": 107 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 97, + "s": [ 100 ], + "e": [ 75.856 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 100, + "s": [ 75.856 ], + "e": [ 0 ] + }, + { "t": 107 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 97, + "op": 107, + "st": 61, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 11, + "ty": 4, + "nm": "S4-Y 2", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 156.45, -23.05 ], + [ 132, 2.75 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 97, + "s": [ 87 ], + "e": [ 43.833 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 100, + "s": [ 43.833 ], + "e": [ 0 ] + }, + { "t": 107 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 97, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 100, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 107 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 97, + "op": 107, + "st": 61, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 12, + "ty": 4, + "nm": "S3-Y 2", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 166.731, -7.927 ], + [ 136.731, 7.115 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 97, + "s": [ 87 ], + "e": [ 42.133 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 100, + "s": [ 42.133 ], + "e": [ 0 ] + }, + { "t": 107 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 97, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 100, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 107 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 97, + "op": 107, + "st": 61, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 13, + "ty": 4, + "nm": "S6-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ -87.5, 20.95 ], + [ -48.75, 54.75 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 54, + "s": [ 87 ], + "e": [ 43.933 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 57, + "s": [ 43.933 ], + "e": [ 0 ] + }, + { "t": 64 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 54, + "s": [ 100 ], + "e": [ 70.456 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 57, + "s": [ 70.456 ], + "e": [ 0 ] + }, + { "t": 64 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 54, + "op": 64, + "st": 18, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 14, + "ty": 4, + "nm": "S5-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ -94.5, 37.073 ], + [ -48.769, 55.365 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 54, + "s": [ 87 ], + "e": [ 50.633 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 57, + "s": [ 50.633 ], + "e": [ 0 ] + }, + { "t": 64 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 54, + "s": [ 100 ], + "e": [ 75.856 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 57, + "s": [ 75.856 ], + "e": [ 0 ] + }, + { "t": 64 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 54, + "op": 64, + "st": 18, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 15, + "ty": 4, + "nm": "S4-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 7.45, 21.95 ], + [ -32.75, 55.75 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 54, + "s": [ 87 ], + "e": [ 43.833 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 57, + "s": [ 43.833 ], + "e": [ 0 ] + }, + { "t": 64 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 54, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 57, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 64 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 54, + "op": 64, + "st": 18, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 16, + "ty": 4, + "nm": "S3-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 16.231, 39.073 ], + [ -32.769, 57.365 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 54, + "s": [ 87 ], + "e": [ 42.133 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 57, + "s": [ 42.133 ], + "e": [ 0 ] + }, + { "t": 64 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 54, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 57, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 64 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 2 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 54, + "op": 64, + "st": 18, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 17, + "ty": 4, + "nm": "S8", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ -0.148, 14.256 ], + [ 10.476, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ -8.551, -8.263 ], + [ -21.454, 0 ], + [ 0, 0 ] + ], + "v": [ + [ -3, 35.95 ], + [ -1.352, -6.756 ], + [ -32.046, -20.579 ], + [ -42.25, 4.25 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 65, + "s": [ 87 ], + "e": [ 21.233 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 70, + "s": [ 21.233 ], + "e": [ 0 ] + }, + { "t": 75 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 65, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 70, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 75 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 1.5 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 65, + "op": 75, + "st": 29, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 18, + "ty": 4, + "nm": "S7", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 27, 1.45 ], + [ 31.046, -1.421 ], + [ 0, 0 ] + ], + "o": [ + [ -27, -1.45 ], + [ -26.426, 1.21 ], + [ 0, 0 ] + ], + "v": [ + [ 34.5, -13.05 ], + [ -35.046, -35.579 ], + [ -62.25, -5.75 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 65, + "s": [ 87 ], + "e": [ 21.233 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 70, + "s": [ 21.233 ], + "e": [ 0 ] + }, + { "t": 75 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 65, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 70, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 75 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 1.5 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 65, + "op": 75, + "st": 29, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 19, + "ty": 4, + "nm": "S2-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 1.9, -10.768 ], + [ 1, -19 ] + ], + "o": [ + [ 0, 0 ], + [ -3.167, 17.951 ], + [ -1, 19 ] + ], + "v": [ + [ -67.25, -105.5 ], + [ -72.333, -84.201 ], + [ -76.5, -37.75 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 29, + "s": [ 87 ], + "e": [ 25.333 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 33, + "s": [ 25.333 ], + "e": [ 0 ] + }, + { "t": 36 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 29, + "s": [ 100 ], + "e": [ 69.056 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 33, + "s": [ 69.056 ], + "e": [ 0 ] + }, + { "t": 36 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 1.5 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 30, + "op": 37, + "st": -7, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 20, + "ty": 4, + "nm": "S1-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 25.043, 45.678, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 1.9, -10.768 ], + [ 1, -19 ] + ], + "o": [ + [ 0, 0 ], + [ -3.167, 17.951 ], + [ -1, 19 ] + ], + "v": [ + [ -67.125, -112 ], + [ -75.458, -89.951 ], + [ -80.375, -39.25 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 29, + "s": [ 87 ], + "e": [ 37.533 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 33, + "s": [ 37.533 ], + "e": [ 0 ] + }, + { "t": 36 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 29, + "s": [ 100 ], + "e": [ 66.356 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 33, + "s": [ 66.356 ], + "e": [ 0 ] + }, + { "t": 36 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 1.5 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 30, + "op": 37, + "st": -7, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 21, + "ty": 4, + "nm": "Dot1", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.833, + "y": 0.833 + }, + "o": { + "x": 0.823, + "y": 0 + }, + "n": "0p833_0p833_0p823_0", + "t": -3, + "s": [ 295.771, 108.994, 0 ], + "e": [ 35.771, 108.994, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 16 } + ] + }, + "a": { "k": [ 196.791, 266.504, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "d": 1, + "ty": "el", + "s": { "k": [ 9.4, 9.4 ] }, + "p": { "k": [ 0.8, -0.5 ] }, + "nm": "Ellipse Path 1" + }, + { + "ty": "fl", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "nm": "Fill 1" + }, + { + "ty": "tr", + "p": { + "k": [ 196, 267 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Ellipse 1" + } + ], + "ip": -5, + "op": 17, + "st": -36, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 22, + "ty": 4, + "nm": "L-B", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 39.043, 45.678, 0 ] }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 25.671, -4.167 ], + [ 1.456, 6.902 ], + [ -8.481, 1.863 ], + [ -47.562, 13.01 ], + [ -0.501, 0.133 ], + [ -71.423, -2.315 ] + ], + "o": [ + [ 0, 0 ], + [ -8.224, 1.335 ], + [ -1.456, -6.903 ], + [ 23.817, -5.233 ], + [ 0.16, -0.044 ], + [ 0.501, -0.133 ], + [ 0, 0 ] + ], + "v": [ + [ -8.837, -58.229 ], + [ -35.834, 33.662 ], + [ -51.688, 23.148 ], + [ -41.174, 7.293 ], + [ 51.797, 44.178 ], + [ 53.188, 43.741 ], + [ 140.394, 43.672 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 0, 0.48, 0.53, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.194 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 166.029, 270.643 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 8" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.703 ], + "y": [ 0.821 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p703_0p821_0p167_0p167" ], + "t": 18, + "s": [ 80 ], + "e": [ 50 ] + }, + { + "i": { + "x": [ 0.263 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.037 ], + "y": [ 0.168 ] + }, + "n": [ "0p263_1_0p037_0p168" ], + "t": 23, + "s": [ 50 ], + "e": [ 30 ] + }, + { "t": 55 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.337 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p337_1_0p167_0p167" ], + "t": 18, + "s": [ 81 ], + "e": [ 73.4 ] + }, + { "t": 29 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + } + ], + "ip": 18, + "op": 179, + "st": 8, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 23, + "ty": 4, + "nm": "L-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 39.043, 45.678, 0 ] }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 25.671, -4.167 ], + [ 1.456, 6.902 ], + [ -8.481, 1.863 ], + [ -47.562, 13.01 ], + [ -0.501, 0.133 ], + [ -71.423, -2.315 ] + ], + "o": [ + [ 0, 0 ], + [ -8.224, 1.335 ], + [ -1.456, -6.903 ], + [ 23.817, -5.233 ], + [ 0.16, -0.044 ], + [ 0.501, -0.133 ], + [ 0, 0 ] + ], + "v": [ + [ -8.837, -58.229 ], + [ -35.834, 33.662 ], + [ -51.688, 23.148 ], + [ -41.174, 7.293 ], + [ 51.797, 44.178 ], + [ 53.188, 43.741 ], + [ 140.394, 43.672 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 8.4 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 166.029, 270.643 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 8" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.703 ], + "y": [ 0.857 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p703_0p857_0p167_0p167" ], + "t": 16, + "s": [ 80 ], + "e": [ 50 ] + }, + { + "i": { + "x": [ 0.938 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.333 ], + "y": [ 0.202 ] + }, + "n": [ "0p938_1_0p333_0p202" ], + "t": 20, + "s": [ 50 ], + "e": [ 0 ] + }, + { "t": 28 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.337 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p337_1_0p167_0p167" ], + "t": 16, + "s": [ 81 ], + "e": [ 73.4 ] + }, + { "t": 27 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + } + ], + "ip": 16, + "op": 179, + "st": 8, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 24, + "ty": 1, + "nm": "N", + "parent": 0, + "ks": { + "o": { "k": 0 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.26, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p26_1_0p167_0p167", + "t": 28, + "s": [ -33.667, 8.182, 0 ], + "e": [ -33.667, -72.818, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.833, + "y": 0.833 + }, + "o": { + "x": 0.74, + "y": 0 + }, + "n": "0p833_0p833_0p74_0", + "t": 40, + "s": [ -33.667, -72.818, 0 ], + "e": [ -33.667, 102.057, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 54 } + ] + }, + "a": { "k": [ 60, 60, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "sw": 120, + "sh": 120, + "sc": "#ffffff", + "ip": 28, + "op": 54, + "st": 0, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 25, + "ty": 4, + "nm": "Dot-Y", + "parent": 24, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.833, + "y": 0.833 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p833_0p833_0p167_0p167", + "t": 28, + "s": [ 39.875, 60, 0 ], + "e": [ 79.375, 60, 0 ], + "to": [ 6.58333349227905, 0, 0 ], + "ti": [ -6.58333349227905, 0, 0 ] + }, + { "t": 54 } + ] + }, + "a": { "k": [ 196.791, 266.504, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "d": 1, + "ty": "el", + "s": { "k": [ 9.4, 9.4 ] }, + "p": { "k": [ 0.8, -0.5 ] }, + "nm": "Ellipse Path 1" + }, + { + "ty": "fl", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "nm": "Fill 1" + }, + { + "ty": "tr", + "p": { + "k": [ 196, 267 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Ellipse 1" + } + ], + "ip": 28, + "op": 54, + "st": 4, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 26, + "ty": 4, + "nm": "T1a-B", + "parent": 36, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 250, 250, 0 ] }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ -0.5, 9.501 ], + [ -0.048, 5.655 ], + [ 0.054, 0.06 ], + [ 0.946, 1.486 ], + [ -9.967, 8.05 ], + [ -40.546, 0 ] + ], + "o": [ + [ 0.031, -0.594 ], + [ 0.076, -8.978 ], + [ -1.161, -1.3 ], + [ -5.939, -9.327 ], + [ 24.677, -19.929 ], + [ 0, 0 ] + ], + "v": [ + [ -30.72, 63.761 ], + [ -30.741, 45.192 ], + [ -37.397, 27.014 ], + [ -40.698, 22.661 ], + [ -37.873, -7.117 ], + [ 49.506, 11.559 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": 24.9, + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.673 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p673_1_0p167_0p167" ], + "t": 70, + "s": [ 24.9 ], + "e": [ 89.1 ] + }, + { "t": 84 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.194 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 227.677, 234.375 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 9" + } + ], + "ip": 70, + "op": 179, + "st": 17, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 27, + "ty": 4, + "nm": "T2a-B", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 39.043, 45.678, 0 ] }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 1.681, -29.992 ], + [ -1.681, 29.992 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.06 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p06_1_0p167_0p167" ], + "t": 75, + "s": [ 50 ], + "e": [ 0 ] + }, + { "t": 85 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.06 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p06_1_0p167_0p167" ], + "t": 75, + "s": [ 50 ], + "e": [ 100 ] + }, + { "t": 85 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 0, 0.48, 0.53, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.194 }, + "lc": 3, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 277.698, 247.258 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 7" + } + ], + "ip": 75, + "op": 179, + "st": 15, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 28, + "ty": 4, + "nm": "T1a-Y 2", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.667, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p667_1_0p167_0p167", + "t": 56, + "s": [ 39.043, 48.678, 0 ], + "e": [ 39.043, 45.678, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 64 } + ] + }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ -0.5, 9.501 ], + [ -0.048, 5.655 ], + [ 0.054, 0.06 ], + [ 0.946, 1.486 ], + [ -9.967, 8.05 ], + [ -40.546, 0 ] + ], + "o": [ + [ 0.031, -0.594 ], + [ 0.076, -8.978 ], + [ -1.161, -1.3 ], + [ -5.939, -9.327 ], + [ 24.677, -19.929 ], + [ 0, 0 ] + ], + "v": [ + [ -30.72, 63.761 ], + [ -30.741, 45.192 ], + [ -37.397, 27.014 ], + [ -40.698, 22.661 ], + [ -37.873, -7.117 ], + [ 49.506, 11.559 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.301 ], + "y": [ 0 ] + }, + "n": [ "0p833_1_0p301_0" ], + "t": 54, + "s": [ 0 ], + "e": [ 24.9 ] + }, + { "t": 70 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.667 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.301 ], + "y": [ 0 ] + }, + "n": [ "0p667_1_0p301_0" ], + "t": 54, + "s": [ 0 ], + "e": [ 100 ] + }, + { "t": 78 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 0, 0.48, 0.53, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 8.4 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 227.677, 234.375 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 9" + } + ], + "ip": 59, + "op": 179, + "st": 12, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 29, + "ty": 4, + "nm": "O-B", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.833, + "y": 0.833 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p833_0p833_0p167_0p167", + "t": 31, + "s": [ -62.792, 73.057, 0 ], + "e": [ -53.792, 7.557, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.638, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.198 + }, + "n": "0p638_1_0p167_0p198", + "t": 35.257, + "s": [ -53.792, 7.557, 0 ], + "e": [ -33.667, -72.818, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ -19.1562919616699, 1.73831975460052, 0 ] + }, + { + "i": { + "x": 0.795, + "y": 1 + }, + "o": { + "x": 0.523, + "y": 0 + }, + "n": "0p795_1_0p523_0", + "t": 44, + "s": [ -33.667, -72.818, 0 ], + "e": [ -14.167, 102.182, 0 ], + "to": [ 16.2075271606445, -1.47073686122894, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.348, + "y": 1 + }, + "o": { + "x": 0.18, + "y": 0 + }, + "n": "0p348_1_0p18_0", + "t": 54, + "s": [ -14.167, 102.182, 0 ], + "e": [ -14.167, 59.182, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.27, + "y": 1 + }, + "o": { + "x": 0.693, + "y": 0 + }, + "n": "0p27_1_0p693_0", + "t": 63, + "s": [ -14.167, 59.182, 0 ], + "e": [ -14.167, 62.182, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 73 } + ] + }, + "a": { "k": [ 196.791, 266.504, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "d": 1, + "ty": "el", + "s": { + "k": [ + { + "i": { + "x": [ 0.667, 0.667 ], + "y": [ 1, 1 ] + }, + "o": { + "x": [ 0.333, 0.333 ], + "y": [ 0, 0 ] + }, + "n": [ "0p667_1_0p333_0", "0p667_1_0p333_0" ], + "t": 54, + "s": [ 3, 3 ], + "e": [ 44.6, 44.6 ] + }, + { "t": 61 } + ] + }, + "p": { "k": [ 0.8, -0.5 ] }, + "nm": "Ellipse Path 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 0, 0.48, 0.53, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.194 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 196, 267 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Ellipse 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 54, + "s": [ 0 ], + "e": [ 30 ] + }, + { + "i": { + "x": [ 0.432 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 1.124 ] + }, + "n": [ "0p432_1_0p167_1p124" ], + "t": 63, + "s": [ 30 ], + "e": [ 39.9 ] + }, + { "t": 91 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 54, + "s": [ 100 ], + "e": [ 88 ] + }, + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 63, + "s": [ 88 ], + "e": [ 88 ] + }, + { "t": 91 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + } + ], + "ip": 54, + "op": 179, + "st": 4, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 30, + "ty": 4, + "nm": "O-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.833, + "y": 0.833 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p833_0p833_0p167_0p167", + "t": 31, + "s": [ -62.792, 73.057, 0 ], + "e": [ -53.792, 7.557, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.638, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.198 + }, + "n": "0p638_1_0p167_0p198", + "t": 35.257, + "s": [ -53.792, 7.557, 0 ], + "e": [ -33.667, -72.818, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ -19.1562919616699, 1.73831975460052, 0 ] + }, + { + "i": { + "x": 0.795, + "y": 1 + }, + "o": { + "x": 0.523, + "y": 0 + }, + "n": "0p795_1_0p523_0", + "t": 44, + "s": [ -33.667, -72.818, 0 ], + "e": [ -14.167, 102.182, 0 ], + "to": [ 16.2075271606445, -1.47073686122894, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.348, + "y": 1 + }, + "o": { + "x": 0.18, + "y": 0 + }, + "n": "0p348_1_0p18_0", + "t": 54, + "s": [ -14.167, 102.182, 0 ], + "e": [ -14.167, 59.182, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.27, + "y": 1 + }, + "o": { + "x": 0.693, + "y": 0 + }, + "n": "0p27_1_0p693_0", + "t": 63, + "s": [ -14.167, 59.182, 0 ], + "e": [ -14.167, 62.182, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 73 } + ] + }, + "a": { "k": [ 196.791, 266.504, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "d": 1, + "ty": "el", + "s": { + "k": [ + { + "i": { + "x": [ 0.667, 0.667 ], + "y": [ 1, 1 ] + }, + "o": { + "x": [ 0.333, 0.333 ], + "y": [ 0, 0 ] + }, + "n": [ "0p667_1_0p333_0", "0p667_1_0p333_0" ], + "t": 54, + "s": [ 3, 3 ], + "e": [ 44.6, 44.6 ] + }, + { "t": 61 } + ] + }, + "p": { "k": [ 0.8, -0.5 ] }, + "nm": "Ellipse Path 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 8.8 }, + "lc": 1, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 196, 267 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Ellipse 1" + } + ], + "ip": 54, + "op": 179, + "st": 4, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 31, + "ty": 4, + "nm": "T1b-B", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 39.043, 45.678, 0 ] }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 1.768, -25.966 ], + [ -1.768, 25.966 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": 0, + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.21 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p21_1_0p167_0p167" ], + "t": 81, + "s": [ 11.7 ], + "e": [ 100 ] + }, + { "t": 88 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.194 }, + "lc": 2, + "lj": 2, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 242.756, 265.581 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 10" + } + ], + "ip": 81, + "op": 179, + "st": 26, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 32, + "ty": 4, + "nm": "T1b-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 39.043, 45.678, 0 ] }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 1.768, -25.966 ], + [ -1.768, 25.966 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 70, + "s": [ 0 ], + "e": [ 0 ] + }, + { "t": 75 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 70, + "s": [ 11.7 ], + "e": [ 100 ] + }, + { "t": 75 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 0, 0.48, 0.53, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 8.4 }, + "lc": 2, + "lj": 2, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 242.756, 265.581 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 10" + } + ], + "ip": 70, + "op": 161, + "st": 15, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 33, + "ty": 4, + "nm": "T2b-B", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 39.043, 45.678, 0 ] }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 246.65, 213.814 ], + [ 340.956, 213.628 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_1_0p167_0p167" ], + "t": 82, + "s": [ 29 ], + "e": [ 0 ] + }, + { "t": 91 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_1_0p167_0p167" ], + "t": 82, + "s": [ 41.1 ], + "e": [ 66.5 ] + }, + { "t": 91 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 0, 0.48, 0.53, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.194 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 5" + } + ], + "ip": 82, + "op": 179, + "st": -17, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 34, + "ty": 4, + "nm": "T2a-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 39.043, 45.678, 0 ] }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 1.681, -29.992 ], + [ -1.681, 29.992 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.06 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p06_1_0p167_0p167" ], + "t": 72, + "s": [ 50 ], + "e": [ 0 ] + }, + { "t": 82 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.06 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p06_1_0p167_0p167" ], + "t": 72, + "s": [ 50 ], + "e": [ 100 ] + }, + { "t": 82 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.194 }, + "lc": 3, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 277.698, 247.258 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 7" + } + ], + "ip": 72, + "op": 89, + "st": 12, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 35, + "ty": 4, + "nm": "T2b-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 39.043, 45.678, 0 ] }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 246.65, 213.814 ], + [ 340.956, 213.628 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_1_0p167_0p167" ], + "t": 76, + "s": [ 29 ], + "e": [ 0 ] + }, + { "t": 85 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_1_0p167_0p167" ], + "t": 76, + "s": [ 41.1 ], + "e": [ 66.5 ] + }, + { "t": 85 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.194 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 5" + } + ], + "ip": 76, + "op": 92, + "st": -23, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 36, + "ty": 4, + "nm": "T1a-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.667, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p667_1_0p167_0p167", + "t": 56, + "s": [ 39.043, 48.678, 0 ], + "e": [ 39.043, 45.678, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 64 } + ] + }, + "a": { "k": [ 250, 250, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ -0.5, 9.501 ], + [ -0.048, 5.655 ], + [ 0.054, 0.06 ], + [ 0.946, 1.486 ], + [ -9.967, 8.05 ], + [ -40.546, 0 ] + ], + "o": [ + [ 0.031, -0.594 ], + [ 0.076, -8.978 ], + [ -1.161, -1.3 ], + [ -5.939, -9.327 ], + [ 24.677, -19.929 ], + [ 0, 0 ] + ], + "v": [ + [ -30.72, 63.761 ], + [ -30.741, 45.192 ], + [ -37.397, 27.014 ], + [ -40.698, 22.661 ], + [ -37.873, -7.117 ], + [ 49.506, 11.559 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.301 ], + "y": [ 0 ] + }, + "n": [ "0p833_1_0p301_0" ], + "t": 54, + "s": [ 0 ], + "e": [ 24.9 ] + }, + { "t": 70 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.667 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.301 ], + "y": [ 0 ] + }, + "n": [ "0p667_1_0p301_0" ], + "t": 54, + "s": [ 0 ], + "e": [ 100 ] + }, + { "t": 74 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 8.4 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 227.677, 234.375 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 9" + } + ], + "ip": 59, + "op": 156, + "st": 12, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 37, + "ty": 4, + "nm": "E1-B", + "parent": 38, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 344.672, 214.842, 0 ] }, + "a": { "k": [ 344.672, 214.842, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ -13.664, -0.145 ], + [ 62.163, 0.29 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.562 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 344.672, 214.842 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 2" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 0.12 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_0p12_0p167_0p167" ], + "t": 84, + "s": [ 0 ], + "e": [ 0 ] + }, + { "t": 93 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_1_0p167_0p167" ], + "t": 84, + "s": [ 0 ], + "e": [ 37.5 ] + }, + { "t": 93 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + } + ], + "ip": 84, + "op": 179, + "st": 84, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 38, + "ty": 4, + "nm": "E1-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.12, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p12_1_0p167_0p167", + "t": 79, + "s": [ 113.715, 9.146, 0 ], + "e": [ 137.715, 9.146, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.12, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "n": "0p12_1_0p167_0", + "t": 88, + "s": [ 137.715, 9.146, 0 ], + "e": [ 133.715, 9.146, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 92 } + ] + }, + "a": { "k": [ 344.672, 214.842, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ -13.664, -0.145 ], + [ 62.163, 0.29 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 0, 0.48, 0.53, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 8.4 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 344.672, 214.842 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 2" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 0.12 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_0p12_0p167_0p167" ], + "t": 79, + "s": [ 0 ], + "e": [ 0 ] + }, + { "t": 88 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_1_0p167_0p167" ], + "t": 79, + "s": [ 0 ], + "e": [ 37.5 ] + }, + { "t": 88 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + } + ], + "ip": 79, + "op": 94, + "st": 79, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 39, + "ty": 4, + "nm": "E2-B", + "parent": 40, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 332.05, 237.932, 0 ] }, + "a": { "k": [ 332.05, 237.932, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ -26.67, -0.283 ], + [ 99.171, 0.066 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 0.12 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_0p12_0p167_0p167" ], + "t": 86, + "s": [ 0 ], + "e": [ 0 ] + }, + { "t": 95 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_1_0p167_0p167" ], + "t": 86, + "s": [ 0 ], + "e": [ 43 ] + }, + { "t": 95 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.562 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 331.664, 238.14 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 3" + } + ], + "ip": 86, + "op": 179, + "st": 86, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 40, + "ty": 4, + "nm": "E2-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.12, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p12_1_0p167_0p167", + "t": 83, + "s": [ 109.092, 33.61, 0 ], + "e": [ 121.092, 33.61, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.12, + "y": 0.12 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p12_0p12_0p167_0p167", + "t": 92, + "s": [ 121.092, 33.61, 0 ], + "e": [ 121.092, 33.61, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 96 } + ] + }, + "a": { "k": [ 332.05, 237.932, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ -26.67, -0.283 ], + [ 99.171, 0.066 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 0.12 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_0p12_0p167_0p167" ], + "t": 83, + "s": [ 0 ], + "e": [ 0 ] + }, + { "t": 92 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_1_0p167_0p167" ], + "t": 83, + "s": [ 0 ], + "e": [ 43 ] + }, + { "t": 92 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 0, 0.48, 0.53, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 8.4 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 331.664, 238.14 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 3" + } + ], + "ip": 83, + "op": 96, + "st": 83, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 41, + "ty": 4, + "nm": "I-B", + "parent": 42, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 303.802, 282.182, 0 ] }, + "a": { "k": [ 303.802, 282.182, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 0.859, -21.143 ], + [ -4.359, 70.392 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 0.12 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_0p12_0p167_0p167" ], + "t": 81, + "s": [ 0 ], + "e": [ 0 ] + }, + { "t": 91 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_1_0p167_0p167" ], + "t": 81, + "s": [ 0 ], + "e": [ 45.7 ] + }, + { "t": 91 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.194 }, + "lc": 3, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 304.135, 282.409 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 6" + } + ], + "ip": 81, + "op": 179, + "st": 18, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 42, + "ty": 4, + "nm": "I-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.12, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p12_1_0p167_0p167", + "t": 78, + "s": [ 93.594, 62.861, 0 ], + "e": [ 92.626, 82.829, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.12, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "n": "0p12_1_0p167_0", + "t": 88, + "s": [ 92.626, 82.829, 0 ], + "e": [ 92.844, 77.861, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 92 } + ] + }, + "a": { "k": [ 303.802, 282.182, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ 0.859, -21.143 ], + [ -4.359, 70.392 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 0.12 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_0p12_0p167_0p167" ], + "t": 78, + "s": [ 0 ], + "e": [ 0 ] + }, + { "t": 88 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.12 ], + "y": [ 1 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p12_1_0p167_0p167" ], + "t": 78, + "s": [ 0 ], + "e": [ 45.7 ] + }, + { "t": 88 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 1" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 0, 0.48, 0.53, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 8.4 }, + "lc": 3, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 304.135, 282.409 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 6" + } + ], + "ip": 78, + "op": 93, + "st": 15, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 43, + "ty": 4, + "nm": "E3-B", + "parent": 44, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 345.189, 261.801, 0 ] }, + "a": { "k": [ 345.124, 261.801, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ -13.664, -0.145 ], + [ 75.663, 0.29 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 92, + "s": [ 0 ], + "e": [ 0 ] + }, + { "t": 97 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 92, + "s": [ 0 ], + "e": [ 31.6 ] + }, + { "t": 97 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 2" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.562 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 344.674, 261.877 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 1" + } + ], + "ip": 92, + "op": 179, + "st": 29, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 44, + "ty": 4, + "nm": "E3-Y", + "parent": 0, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.667, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p667_1_0p167_0p167", + "t": 84, + "s": [ 119.167, 57.479, 0 ], + "e": [ 137.167, 57.479, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.667, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "n": "0p667_1_0p167_0", + "t": 92, + "s": [ 137.167, 57.479, 0 ], + "e": [ 134.167, 57.479, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 96 } + ] + }, + "a": { "k": [ 345.124, 261.801, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "k": { + "i": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "o": [ + [ 0, 0 ], + [ 0, 0 ] + ], + "v": [ + [ -13.664, -0.145 ], + [ 75.663, 0.29 ] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "tm", + "s": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 84, + "s": [ 0 ], + "e": [ 0 ] + }, + { "t": 92 } + ], + "ix": 1 + }, + "e": { + "k": [ + { + "i": { + "x": [ 0.833 ], + "y": [ 0.833 ] + }, + "o": { + "x": [ 0.167 ], + "y": [ 0.167 ] + }, + "n": [ "0p833_0p833_0p167_0p167" ], + "t": 84, + "s": [ 0 ], + "e": [ 31.6 ] + }, + { "t": 92 } + ], + "ix": 2 + }, + "o": { + "k": 0, + "ix": 3 + }, + "m": 1, + "ix": 2, + "nm": "Trim Paths 2" + }, + { + "ty": "st", + "fillEnabled": true, + "c": { "k": [ 0, 0.48, 0.53, 1 ] }, + "o": { "k": 100 }, + "w": { "k": 9.562 }, + "lc": 2, + "lj": 1, + "ml": 10, + "nm": "Stroke 1" + }, + { + "ty": "tr", + "p": { + "k": [ 344.674, 261.877 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 1" + } + ], + "ip": 84, + "op": 102, + "st": 21, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 45, + "ty": 4, + "nm": "Dot-Y", + "parent": 46, + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0, + "y": 0.812 + }, + "o": { + "x": 0, + "y": 0 + }, + "n": "0_0p812_0_0", + "t": 96, + "s": [ 43.263, 59.75, 0 ], + "e": [ 62.513, 59.75, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.708, + "y": 1 + }, + "o": { + "x": 0.39, + "y": 0.707 + }, + "n": "0p708_1_0p39_0p707", + "t": 108, + "s": [ 62.513, 59.75, 0 ], + "e": [ 63.763, 59.75, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 115 } + ] + }, + "a": { "k": [ 196.791, 266.504, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "d": 1, + "ty": "el", + "s": { "k": [ 9.2, 9.2 ] }, + "p": { "k": [ 0.8, -0.5 ] }, + "nm": "Ellipse Path 1" + }, + { + "ty": "fl", + "fillEnabled": true, + "c": { "k": [ 1, 1, 1, 1 ] }, + "o": { "k": 100 }, + "nm": "Fill 1" + }, + { + "ty": "tr", + "p": { + "k": [ 196, 267 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Ellipse 1" + } + ], + "ip": 96, + "op": 182, + "st": 65, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 46, + "ty": 1, + "nm": "Bncr", + "parent": 0, + "ks": { + "o": { "k": 0 }, + "r": { "k": 0 }, + "p": { + "k": [ + { + "i": { + "x": 0.18, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p18_1_0p167_0p167", + "t": 96, + "s": [ 164.782, 57.473, 0 ], + "e": [ 164.782, 55.473, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.833, + "y": 0.833 + }, + "o": { + "x": 0.82, + "y": 0 + }, + "n": "0p833_0p833_0p82_0", + "t": 99, + "s": [ 164.782, 55.473, 0 ], + "e": [ 164.782, 57.473, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.18, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0.167 + }, + "n": "0p18_1_0p167_0p167", + "t": 102, + "s": [ 164.782, 57.473, 0 ], + "e": [ 164.782, 56.909, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { + "i": { + "x": 0.833, + "y": 0.833 + }, + "o": { + "x": 0.82, + "y": 0 + }, + "n": "0p833_0p833_0p82_0", + "t": 105, + "s": [ 164.782, 56.909, 0 ], + "e": [ 164.782, 57.473, 0 ], + "to": [ 0, 0, 0 ], + "ti": [ 0, 0, 0 ] + }, + { "t": 108 } + ] + }, + "a": { "k": [ 60, 60, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "sw": 120, + "sh": 120, + "sc": "#ffffff", + "ip": 96, + "op": 182, + "st": 15, + "bm": 0, + "sr": 1 + }, + { + "ddd": 0, + "ind": 47, + "ty": 4, + "nm": "BG", + "ks": { + "o": { "k": 100 }, + "r": { "k": 0 }, + "p": { "k": [ 187.5, 333.5, 0 ] }, + "a": { "k": [ 0, 0, 0 ] }, + "s": { "k": [ 100, 100, 100 ] } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ty": "rc", + "d": 1, + "s": { "k": [ 375, 667 ] }, + "p": { "k": [ 0, 0 ] }, + "r": { "k": 0 }, + "nm": "Rectangle Path 1" + }, + { + "ty": "fl", + "fillEnabled": true, + "c": { "k": [ 0, 0.82, 0.76, 1 ] }, + "o": { "k": 100 }, + "nm": "Fill 1" + }, + { + "ty": "tr", + "p": { + "k": [ 0, 0 ], + "ix": 2 + }, + "a": { + "k": [ 0, 0 ], + "ix": 1 + }, + "s": { + "k": [ 100, 100 ], + "ix": 3 + }, + "r": { + "k": 0, + "ix": 6 + }, + "o": { + "k": 100, + "ix": 7 + }, + "sk": { + "k": 0, + "ix": 4 + }, + "sa": { + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Rectangle 1" + } + ], + "ip": 0, + "op": 179, + "st": 0, + "bm": 0, + "sr": 1 + } + ], + "v": "4.4.26", + "ddd": 0, + "ip": 0, + "op": 179, + "fr": 30, + "w": 375, + "h": 667 +} \ No newline at end of file diff --git a/SimpleLottieIslandApp/Directory.Build.props b/SimpleLottieIslandApp/Directory.Build.props new file mode 100644 index 00000000..09314652 --- /dev/null +++ b/SimpleLottieIslandApp/Directory.Build.props @@ -0,0 +1,7 @@ + + + $([MSBuild]::NormalizeDirectory('$(SolutionDir)', '_build', '$(Platform)', '$(Configuration)')) + $([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'bin')) + $([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'obj')) + + \ No newline at end of file diff --git a/SimpleLottieIslandApp/Project.idl b/SimpleLottieIslandApp/Project.idl new file mode 100644 index 00000000..910be2d6 --- /dev/null +++ b/SimpleLottieIslandApp/Project.idl @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace SimpleLottieIslandApp +{ + /* IDL to generate a placeholder WinMD for the AppX project */ + + [default_interface] + runtimeclass Placeholder + { + Placeholder(); + static Placeholder DoNothing(); + } + +} diff --git a/SimpleLottieIslandApp/Resource.h b/SimpleLottieIslandApp/Resource.h new file mode 100644 index 00000000..ee66d8bd --- /dev/null +++ b/SimpleLottieIslandApp/Resource.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by SimpleIslandApp.rc + +#define IDS_APP_TITLE 103 + +#define IDR_MAINFRAME 128 +#define IDD_SIMPLELOTTIEISLANDAPP_DIALOG 102 +#define IDD_ABOUTBOX 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDI_SIMPLELOTTIEISLANDAPP 107 +#define IDI_SMALL 108 +#define IDC_SIMPLELOTTIEISLANDAPP 109 +#define IDC_MYICON 2 +#ifndef IDC_STATIC +#define IDC_STATIC -1 +#endif +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NO_MFC 130 +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/SimpleLottieIslandApp/SimpleLottieIslandApp.cpp b/SimpleLottieIslandApp/SimpleLottieIslandApp.cpp new file mode 100644 index 00000000..544d869b --- /dev/null +++ b/SimpleLottieIslandApp/SimpleLottieIslandApp.cpp @@ -0,0 +1,483 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// SimpleLottieIslandApp.cpp : Defines the entry point for the application. + +#include "pch.h" +#include "SimpleLottieIslandApp.h" + +#include // For ContentPreTranslateMessage +#include +#include + +namespace winrt +{ + using namespace winrt::Windows::Foundation; + using namespace winrt::Microsoft::UI; + using namespace winrt::Microsoft::UI::Content; + using namespace winrt::Microsoft::UI::Dispatching; + using namespace winrt::CommunityToolkit::WinAppSDK::LottieWinRT; + using namespace winrt::CommunityToolkit::WinAppSDK::LottieIsland; + using float2 = winrt::Windows::Foundation::Numerics::float2; +} + +// Forward declarations of functions included in this code module: +void MyRegisterClass(HINSTANCE hInstance, const wchar_t* szWindowClass); +HWND InitInstance(HINSTANCE, int, const wchar_t* szTitle, const wchar_t* szWindowClass); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); +bool ProcessMessageForTabNavigation(const HWND topLevelWindow, MSG* msg); + +// Extra state for our top-level window, we point to from GWLP_USERDATA. +struct WindowInfo +{ + // winrt::DesktopWindowXamlSource DesktopWindowXamlSource{ nullptr }; + winrt::Microsoft::UI::Composition::Compositor Compositor{}; + winrt::DesktopChildSiteBridge Bridge{ nullptr }; + winrt::event_token TakeFocusRequestedToken{}; + HWND LastFocusedWindow{ NULL }; + winrt::ContentIsland Island{ nullptr }; + bool isPaused = false; +}; + +enum class ButtonType +{ + PlayButton = 1, + PauseButton, + StopButton, + ReverseButton +}; + +constexpr int k_padding = 10; +constexpr int k_buttonWidth = 150; +constexpr int k_buttonHeight = 40; + +void LayoutBridge(WindowInfo* windowInfo, int tlwWidth, int tlwHeight); +void LayoutButton(ButtonType type, int tlwWidth, int tlwHeight, HWND topLevelWindow); +void CreateWin32Button(ButtonType type, const std::wstring_view& text, HWND parentHwnd); +void OnButtonClicked(ButtonType type, WindowInfo* windowInfo, HWND topLevelWindow); +void SetButtonText(ButtonType type, const std::wstring_view& text, HWND topLevelWindow); +void SetPauseState(WindowInfo* windowInfo, bool isPaused, HWND topLevelWindow); + +int APIENTRY wWinMain(_In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPWSTR lpCmdLine, + _In_ int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + try + { + // Island-support: Call init_apartment to initialize COM and WinRT for the thread. + winrt::init_apartment(winrt::apartment_type::single_threaded); + + // Island-support: We must start a DispatcherQueueController before we can create an island or use Xaml. + auto dispatcherQueueController{ winrt::DispatcherQueueController::CreateOnCurrentThread() }; + + // The title bar text + WCHAR szTitle[100]; + winrt::check_bool(LoadStringW(hInstance, IDS_APP_TITLE, szTitle, ARRAYSIZE(szTitle)) != 0); + + // The main window class name + WCHAR szWindowClass[100]; + winrt::check_bool(LoadStringW(hInstance, IDC_SIMPLELOTTIEISLANDAPP, szWindowClass, ARRAYSIZE(szWindowClass)) != 0); + + MyRegisterClass(hInstance, szWindowClass); + + // Perform application initialization: + InitInstance(hInstance, nCmdShow, szTitle, szWindowClass); + + HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SIMPLELOTTIEISLANDAPP)); + + MSG msg{}; + + // Main message loop: + while (GetMessage(&msg, nullptr, 0, 0)) + { + // Island-support: It's important to call ContentPreTranslateMessage in the event loop so that WinAppSDK can be aware of + // the messages. If you don't need to use an accelerator table, you could just call DispatcherQueue.RunEventLoop + // to do the message pump for you (it will call ContentPreTranslateMessage automatically). + if (::ContentPreTranslateMessage(&msg)) + { + continue; + } + + if (TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + continue; + } + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // Island-support: To properly shut down after using a DispatcherQueue, call ShutdownQueue[Aysnc](). + dispatcherQueueController.ShutdownQueue(); + } + catch (const winrt::hresult_error& exception) + { + // An exception was thrown, let's make the exit code the HR value of the exception. + return exception.code().value; + } + + return 0; +} + +// +// FUNCTION: MyRegisterClass() +// +// PURPOSE: Registers the window class. +// +void MyRegisterClass(HINSTANCE hInstance, const wchar_t* szWindowClass) +{ + WNDCLASSEXW wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SIMPLELOTTIEISLANDAPP)); + wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SIMPLELOTTIEISLANDAPP); + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); + + winrt::check_bool(RegisterClassExW(&wcex) != 0); +} + +// +// FUNCTION: InitInstance(HINSTANCE, int) +// +// PURPOSE: Saves instance handle and creates main window +// +// COMMENTS: +// +// In this function, we save the instance handle in a global variable and +// create and display the main program window. +// +HWND InitInstance(HINSTANCE /*hInstance*/, int nCmdShow, const wchar_t* szTitle, const wchar_t* szWindowClass) +{ + HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, ::GetModuleHandle(NULL), nullptr); + winrt::check_bool(hWnd != NULL); + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + return hWnd; +} + +// +// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) +// +// PURPOSE: Processes messages for the main window. +// +// WM_COMMAND - process the application menu +// WM_PAINT - Paint the main window +// WM_DESTROY - post a quit message and return +// +// +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WindowInfo* windowInfo = reinterpret_cast(::GetWindowLongPtr(hWnd, GWLP_USERDATA)); + + switch (message) + { + case WM_CREATE: + { + windowInfo = new WindowInfo(); + ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(windowInfo)); + + // Create the DesktopChildSiteBridge + windowInfo->Bridge = winrt::DesktopChildSiteBridge::Create( + windowInfo->Compositor, + winrt::GetWindowIdFromWindow(hWnd)); + + // Create the LottieIsland, which is a WinRT wrapper for hosting + // a Lottie animation in a ContentIsland + auto lottieIsland = winrt::LottieContentIsland::Create(windowInfo->Compositor); + windowInfo->Island = lottieIsland.Island(); + + // Connect the ContentIsland to the DesktopChildSiteBridge + windowInfo->Bridge.Connect(windowInfo->Island); + windowInfo->Bridge.Show(); + + winrt::LottieVisualSourceWinRT lottieVisualSource = + winrt::LottieVisualSourceWinRT::CreateFromString(L"ms-appx:///LottieLogo1.json"); + lottieVisualSource.AnimatedVisualInvalidated( + [hWnd, lottieIsland, lottieVisualSource, windowInfo](auto&&, auto&&) + { + windowInfo->Compositor.DispatcherQueue().TryEnqueue( + [hWnd, lottieIsland, lottieVisualSource, windowInfo]() + { + winrt::Windows::Foundation::IInspectable diagnostics; + winrt::IAnimatedVisualFrameworkless animatedVisual = + lottieVisualSource.TryCreateAnimatedVisual(windowInfo->Compositor, diagnostics); + + lottieIsland.AnimatedVisual( + animatedVisual.as()); + + // Resize bridge + RECT rect; + GetClientRect(hWnd, &rect); + LayoutBridge(windowInfo, rect.right - rect.left, rect.bottom - rect.top); + }); + }); + + lottieIsland.PointerPressed([=](auto&...) { + // Clicking on the Lottie animation acts like clicking "Pause/Resume" + OnButtonClicked(ButtonType::PauseButton, windowInfo, hWnd); + }); + + // Add some Win32 controls to allow the app to play with the animation + CreateWin32Button(ButtonType::PlayButton, L"Play", hWnd); + CreateWin32Button(ButtonType::PauseButton, L"Pause", hWnd); + CreateWin32Button(ButtonType::StopButton, L"Stop", hWnd); + CreateWin32Button(ButtonType::ReverseButton, L"Reverse", hWnd); + } + break; + case WM_SIZE: + { + const int width = LOWORD(lParam); + const int height = HIWORD(lParam); + + if (windowInfo->Bridge) + { + LayoutBridge(windowInfo, width, height); + } + + LayoutButton(ButtonType::PlayButton, width, height, hWnd); + LayoutButton(ButtonType::PauseButton, width, height, hWnd); + LayoutButton(ButtonType::StopButton, width, height, hWnd); + LayoutButton(ButtonType::ReverseButton, width, height, hWnd); + } + break; + case WM_ACTIVATE: + { + // Make focus work nicely when the user presses alt+tab to activate a different window, and then alt+tab + // again to come back to this window. We want the focus to go back to the same child HWND that was focused + // before. + const bool isGettingDeactivated = (LOWORD(wParam) == WA_INACTIVE); + if (isGettingDeactivated) + { + // Remember the HWND that had focus. + windowInfo->LastFocusedWindow = ::GetFocus(); + } + else if (windowInfo->LastFocusedWindow != NULL) + { + ::SetFocus(windowInfo->LastFocusedWindow); + } + } + break; + case WM_COMMAND: + { + int wmId = LOWORD(wParam); + int wmCode = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDM_ABOUT: + DialogBox(::GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); + break; + case IDM_EXIT: + DestroyWindow(hWnd); + break; + case 501: // Buttons + case 502: + case 503: + case 504: + if (wmCode == BN_CLICKED) + { + ButtonType type = static_cast(wmId - 500); + OnButtonClicked(type, windowInfo, hWnd); + } + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + } + break; + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hWnd, &ps); + // TODO: Add any drawing code that uses hdc here... + UNREFERENCED_PARAMETER(hdc); + EndPaint(hWnd, &ps); + } + break; + case WM_DESTROY: + if (nullptr != windowInfo && nullptr != windowInfo->Island) + { + // Must close the ContentIsland so that it will release the reference to its AppData. + windowInfo->Island.Close(); + } + PostQuitMessage(0); + break; + case WM_NCDESTROY: + delete windowInfo; + ::SetWindowLong(hWnd, GWLP_USERDATA, NULL); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + +// Message handler for about box. +INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + UNREFERENCED_PARAMETER(lParam); + switch (message) + { + case WM_INITDIALOG: + return (INT_PTR)TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return (INT_PTR)TRUE; + } + break; + } + return (INT_PTR)FALSE; +} + +void LayoutBridge(WindowInfo* windowInfo, int width, int height) +{ + // Layout our bridge: we want to use all available height (minus a button and some padding), + // but respect the ratio that the LottieIsland wants to display at. This can be accessed through + // the "RequestedSize" property on the ContentSiteView. + + int availableHeight = height - (k_padding * 3) - k_buttonHeight; + int availableWidth = width - (k_padding * 2); + + + // Check what size the lottie wants to be + winrt::float2 requestedSize = windowInfo->Bridge.SiteView().RequestedSize(); + + // Scale the width to be the ratio the lottie wants + int bridgeWidth = 0; + if (requestedSize.y > 0) // Guard against divide-by-zero + { + bridgeWidth = static_cast((requestedSize.x / requestedSize.y) * availableHeight); + } + + // ... but don't overflow the width we have available + bridgeWidth = std::min(availableWidth, bridgeWidth); + + windowInfo->Bridge.MoveAndResize({ k_padding, k_padding, bridgeWidth, availableHeight }); +} + +void LayoutButton(ButtonType type, int /*tlwWidth*/, int tlwHeight, HWND topLevelWindow) +{ + int buttonIndex = static_cast(type); + + int xPos = ((buttonIndex - 1) * (k_buttonWidth + k_padding)) + k_padding; + int yPos = tlwHeight - k_buttonHeight - k_padding; + + HWND buttonHwnd = ::GetDlgItem(topLevelWindow, 500 + buttonIndex); + ::SetWindowPos(buttonHwnd, NULL, xPos, yPos, k_buttonWidth, k_buttonHeight, SWP_NOZORDER); +} + +void CreateWin32Button(ButtonType type, const std::wstring_view& text, HWND parentHwnd) +{ + int buttonIndex = static_cast(type); + + int xPos = ((buttonIndex - 1) * (k_buttonWidth + k_padding)) + k_padding; + + const HINSTANCE hInst = (HINSTANCE)GetWindowLongPtr(parentHwnd, GWLP_HINSTANCE); + HMENU fakeHMenu = reinterpret_cast(static_cast(500 + buttonIndex)); + ::CreateWindowW( + L"BUTTON", + text.data(), + WS_TABSTOP | WS_VISIBLE | WS_CHILD, + xPos, 250, k_buttonWidth, k_buttonHeight, + parentHwnd, + fakeHMenu, + hInst, + NULL); +} + +void OnButtonClicked(ButtonType type, WindowInfo* windowInfo, HWND topLevelWindow) +{ + winrt::Windows::Foundation::IAsyncAction asyncAction{ nullptr }; + + // We can retrieve the Lottie-specific functionality from the LottieContentIsland via its AppData. + winrt::LottieContentIsland lottieIsland{ windowInfo->Island.AppData().as() }; + + switch (type) + { + case ButtonType::PlayButton: + asyncAction = lottieIsland.PlayAsync(0.0, 1.0, true); + asyncAction.Completed([](auto&&, auto&& asyncStatus) + { + // Check if the async operation was successfully completed + if (asyncStatus == winrt::Windows::Foundation::AsyncStatus::Completed) + { + OutputDebugString(L"Async operation completed successfully.\n"); + } + else + { + OutputDebugString(L"Async operation failed or was canceled.\n"); + } + }); + + + SetPauseState(windowInfo, false, topLevelWindow); + break; + case ButtonType::PauseButton: + if (windowInfo->isPaused) + { + lottieIsland.Resume(); + } + else + { + lottieIsland.Pause(); + } + SetPauseState(windowInfo, !windowInfo->isPaused, topLevelWindow); + break; + case ButtonType::StopButton: + lottieIsland.Stop(); + SetPauseState(windowInfo, false, topLevelWindow); + break; + case ButtonType::ReverseButton: + if (lottieIsland.PlaybackRate() == 1.0) + { + lottieIsland.PlaybackRate(-1.0); + } + else + { + lottieIsland.PlaybackRate(1.0); + } + break; + default: + throw winrt::hresult_invalid_argument{ L"Invalid button type." }; + } +} + +void SetButtonText(ButtonType type, const std::wstring_view& text, HWND topLevelWindow) +{ + int buttonIndex = static_cast(type); + HWND buttonHwnd = ::GetDlgItem(topLevelWindow, 500 + buttonIndex); + ::SendMessageW(buttonHwnd, WM_SETTEXT, 0, reinterpret_cast(text.data())); +} + +void SetPauseState(WindowInfo* windowInfo, bool isPaused, HWND topLevelWindow) +{ + if (windowInfo->isPaused == isPaused) + { + return; + } + + SetButtonText(ButtonType::PauseButton, + isPaused ? L"Resume" : L"Pause", + topLevelWindow); + + windowInfo->isPaused = isPaused; +} diff --git a/SimpleLottieIslandApp/SimpleLottieIslandApp.h b/SimpleLottieIslandApp/SimpleLottieIslandApp.h new file mode 100644 index 00000000..385a70ac --- /dev/null +++ b/SimpleLottieIslandApp/SimpleLottieIslandApp.h @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once + +#include "resource.h" diff --git a/SimpleLottieIslandApp/SimpleLottieIslandApp.ico b/SimpleLottieIslandApp/SimpleLottieIslandApp.ico new file mode 100644 index 00000000..b3ec03bd Binary files /dev/null and b/SimpleLottieIslandApp/SimpleLottieIslandApp.ico differ diff --git a/SimpleLottieIslandApp/SimpleLottieIslandApp.rc b/SimpleLottieIslandApp/SimpleLottieIslandApp.rc new file mode 100644 index 00000000..a2e45d9f Binary files /dev/null and b/SimpleLottieIslandApp/SimpleLottieIslandApp.rc differ diff --git a/SimpleLottieIslandApp/SimpleLottieIslandApp.vcxproj b/SimpleLottieIslandApp/SimpleLottieIslandApp.vcxproj new file mode 100644 index 00000000..d3d9e738 --- /dev/null +++ b/SimpleLottieIslandApp/SimpleLottieIslandApp.vcxproj @@ -0,0 +1,215 @@ + + + + + + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {350A5EC2-B156-4AAF-9D80-A864C76BA0C5} + SimpleLottieIslandApp + + Windows Store + 10.0 + + + true + true + true + true + SimpleLottieIslandApp + SimpleLottieIslandApp + $(RootNamespace) + en-US + false + 10.0 + 10.0 + + 10.0.17763.0 + true + + + + Application + true + v143 + Unicode + true + + + true + true + + + false + true + false + + + + + + + + + + + + + + Use + pch.h + $(IntDir)pch.pch + + + user32.lib;Ole32.lib;%(AdditionalDependencies) + Microsoft.UI.Windowing.Core.dll + + + + + Level4 + true + true + _WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + + + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + true + true + + + + + + + + + + + Create + + + + + + + + + + + + + + true + Document + + + + + + Designer + + + + + + + + {9ba7a2f2-b723-458b-a575-3f726d271465} + + + {dda0d223-4b59-455d-a8b1-cfae59523ffb} + + + + + $(Platform) + x86 + x64 + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + \ No newline at end of file diff --git a/SimpleLottieIslandApp/SimpleLottieIslandApp.vcxproj.filters b/SimpleLottieIslandApp/SimpleLottieIslandApp.vcxproj.filters new file mode 100644 index 00000000..b3f8cbe1 --- /dev/null +++ b/SimpleLottieIslandApp/SimpleLottieIslandApp.vcxproj.filters @@ -0,0 +1,69 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + + + + + + + + + + + + + + + Source Files + + + \ No newline at end of file diff --git a/SimpleLottieIslandApp/package.appxmanifest b/SimpleLottieIslandApp/package.appxmanifest new file mode 100644 index 00000000..b0c5b552 --- /dev/null +++ b/SimpleLottieIslandApp/package.appxmanifest @@ -0,0 +1,60 @@ + + + + + + SimpleLottieIslandApp + Microsoft Corporation + Assets\logo.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SimpleLottieIslandApp/packages.config b/SimpleLottieIslandApp/packages.config new file mode 100644 index 00000000..a9654c5f --- /dev/null +++ b/SimpleLottieIslandApp/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/SimpleLottieIslandApp/pch.cpp b/SimpleLottieIslandApp/pch.cpp new file mode 100644 index 00000000..b7f2ce9c --- /dev/null +++ b/SimpleLottieIslandApp/pch.cpp @@ -0,0 +1,3 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" diff --git a/SimpleLottieIslandApp/pch.h b/SimpleLottieIslandApp/pch.h new file mode 100644 index 00000000..f9c5d52c --- /dev/null +++ b/SimpleLottieIslandApp/pch.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once + +#include "targetver.h" +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define NOMINMAX +// Windows Header Files +#include + +// There's an API named GetCurrentTime in the Storyboard type. +#undef GetCurrentTime + +// Com and WinRT headers +#include + +// Some generated files, like MainPage.xaml.g.h need files such as Microsoft.UI.Xaml.Markup.h +// to already be included. Let's just include a bunch of stuff we know we'll need here in the PCH. +#include +#include +#include +#include +#include diff --git a/SimpleLottieIslandApp/small.ico b/SimpleLottieIslandApp/small.ico new file mode 100644 index 00000000..b3ec03bd Binary files /dev/null and b/SimpleLottieIslandApp/small.ico differ diff --git a/SimpleLottieIslandApp/targetver.h b/SimpleLottieIslandApp/targetver.h new file mode 100644 index 00000000..2a0d857d --- /dev/null +++ b/SimpleLottieIslandApp/targetver.h @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// // Including SDKDDKVer.h defines the highest available Windows platform. +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. +#include diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4e11b0db..2d89c8a0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -53,6 +53,11 @@ steps: - powershell: .\build\Install-WindowsSdkISO.ps1 18362 displayName: Insider SDK +# Restore the solution +- script: | + nuget restore Lottie-Windows.sln + displayName: Nuget Restore LottieIsland + # Run the build. - powershell: .\build.ps1 --target=Package displayName: Build diff --git a/build/build.cake b/build/build.cake index 8e4cbdc2..2c5b75c8 100644 --- a/build/build.cake +++ b/build/build.cake @@ -67,7 +67,9 @@ void MSBuildSolution( // Build one native and one MSIL version of each project. foreach (var platformTarget in new [] { + PlatformTarget.x64, PlatformTarget.x86, + PlatformTarget.ARM64, PlatformTarget.MSIL, }) { diff --git a/nuget.config b/nuget.config new file mode 100644 index 00000000..de291b7f --- /dev/null +++ b/nuget.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/source/Lottie/AnimatedVisualFactory.cs b/source/Lottie/AnimatedVisualFactory.cs index b8887c19..2aa8dec1 100644 --- a/source/Lottie/AnimatedVisualFactory.cs +++ b/source/Lottie/AnimatedVisualFactory.cs @@ -10,7 +10,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using CommunityToolkit.WinUI.Lottie.UIData.Tools; -using Microsoft.UI.Xaml.Controls; #if WINAPPSDK using Microsoft.UI.Composition; @@ -18,6 +17,15 @@ using Windows.UI.Composition; #endif +#if WINAPPSDK +using IAnimatedVisual = CommunityToolkit.WinAppSDK.LottieIsland.IAnimatedVisualFrameworkless; +using IAnimatedVisualSource = object; +#pragma warning disable SA1121 // Use built-in type alias +#else +using IAnimatedVisual = Microsoft.UI.Xaml.Controls.IAnimatedVisual; +using IAnimatedVisualSource = Microsoft.UI.Xaml.Controls.IAnimatedVisualSource; +#endif + namespace CommunityToolkit.WinUI.Lottie { /// @@ -135,4 +143,4 @@ internal void SetRootVisual(WinCompData.Visual rootVisual) return result; } } -} +} \ No newline at end of file diff --git a/source/Lottie/DisposableAnimatedVisual.cs b/source/Lottie/DisposableAnimatedVisual.cs index 587c16f4..1332a03d 100644 --- a/source/Lottie/DisposableAnimatedVisual.cs +++ b/source/Lottie/DisposableAnimatedVisual.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using System.Numerics; -using Microsoft.UI.Xaml.Controls; #if WINAPPSDK using Microsoft.UI.Composition; @@ -15,6 +14,14 @@ using Windows.UI.Composition; #endif +#if WINAPPSDK +using IAnimatedVisual = CommunityToolkit.WinAppSDK.LottieIsland.IAnimatedVisualFrameworkless; +using IAnimatedVisualSource = object; +#else +using IAnimatedVisual = Microsoft.UI.Xaml.Controls.IAnimatedVisual; +using IAnimatedVisualSource = Microsoft.UI.Xaml.Controls.IAnimatedVisualSource; +#endif + namespace CommunityToolkit.WinUI.Lottie { sealed class DisposableAnimatedVisual : IAnimatedVisual, IDisposable diff --git a/source/Lottie/DotLottieLoader.cs b/source/Lottie/DotLottieLoader.cs index 82d9146a..853edcb1 100644 --- a/source/Lottie/DotLottieLoader.cs +++ b/source/Lottie/DotLottieLoader.cs @@ -14,7 +14,7 @@ #if WINAPPSDK using Microsoft.UI.Composition; -using Microsoft.UI.Xaml.Media; + #else using Windows.UI.Composition; using Windows.UI.Xaml.Media; @@ -97,7 +97,10 @@ sealed class DotLottieLoader : Loader return null; } - return LoadedImageSurface.StartLoadFromStream(imageStream.AsRandomAccessStream()); + // TODO - Load this image some other way + return null; + + //return LoadedImageSurface.StartLoadFromStream(imageStream.AsRandomAccessStream()); } public override void Dispose() diff --git a/source/Lottie/Instantiator.cs b/source/Lottie/Instantiator.cs index 8fc44394..f7c9169b 100644 --- a/source/Lottie/Instantiator.cs +++ b/source/Lottie/Instantiator.cs @@ -20,7 +20,7 @@ using Mgce = Microsoft.Graphics.Canvas.Effects; #if WINAPPSDK using Wc = Microsoft.UI.Composition; -using Wm = Microsoft.UI.Xaml.Media; + #else using Wc = Windows.UI.Composition; using Wm = Windows.UI.Xaml.Media; @@ -1592,7 +1592,9 @@ Wc.CompositionRadialGradientBrush GetCompositionRadialGradientBrush(Wd.Compositi { case Wmd.LoadedImageSurface.LoadedImageSurfaceType.FromStream: var bytes = ((Wmd.LoadedImageSurfaceFromStream)obj).Bytes; - result = Wm.LoadedImageSurface.StartLoadFromStream(bytes.AsBuffer().AsStream().AsRandomAccessStream()); + + // TODO - load this image some other way + // result = Wm.LoadedImageSurface.StartLoadFromStream(bytes.AsBuffer().AsStream().AsRandomAccessStream()); break; case Wmd.LoadedImageSurface.LoadedImageSurfaceType.FromUri: var uri = ((Wmd.LoadedImageSurfaceFromUri)obj).Uri; diff --git a/source/Lottie/LottieVisualSource.cs b/source/Lottie/LottieVisualSource.cs index ecb12520..f60cb718 100644 --- a/source/Lottie/LottieVisualSource.cs +++ b/source/Lottie/LottieVisualSource.cs @@ -10,7 +10,6 @@ using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; using CommunityToolkit.WinUI.Lottie; -using Microsoft.UI.Xaml.Controls; using Windows.Foundation; using Windows.Foundation.Metadata; using Windows.Storage; @@ -18,20 +17,41 @@ #if WINAPPSDK using Microsoft.UI.Composition; -using Microsoft.UI.Xaml; #else +using Microsoft.UI.Xaml.Controls; using Windows.UI.Composition; using Windows.UI.Xaml; #endif +#if WINAPPSDK +using IAnimatedVisual = CommunityToolkit.WinAppSDK.LottieIsland.IAnimatedVisualFrameworkless; +using IAnimatedVisualSource = CommunityToolkit.WinUI.Lottie.LottieVisualSource; +using IDynamicAnimatedVisualSource = CommunityToolkit.WinUI.Lottie.LottieVisualSource; +#pragma warning disable SA1121 // Use built-in type alias +#else +using IAnimatedVisual = Microsoft.UI.Xaml.Controls.IAnimatedVisual; +using IAnimatedVisualSource = Microsoft.UI.Xaml.Controls.IAnimatedVisualSource; +using IDynamicAnimatedVisualSource = Microsoft.UI.Xaml.Controls.IDynamicAnimatedVisualSource; +#endif + namespace CommunityToolkit.WinUI.Lottie { +#if WINAPPSDK + /// + /// A class for a Lottie composition. This allows + /// a Lottie to be specified as source of a . + /// + public sealed class LottieVisualSource + { +#else /// /// An for a Lottie composition. This allows /// a Lottie to be specified as the source for a . /// public sealed class LottieVisualSource : DependencyObject, IDynamicAnimatedVisualSource { +#endif + #if WINAPPSDK HashSet> _compositionInvalidatedEventTokenTable = new HashSet>(); #else @@ -42,7 +62,9 @@ public sealed class LottieVisualSource : DependencyObject, IDynamicAnimatedVisua Uri? _uriSource; AnimatedVisualFactory? _animatedVisualFactory; ImageAssetHandler? _imageAssetHandler; - +#if WINAPPSDK + LottieVisualOptions _options; +#else /// /// Gets the options for the . /// @@ -68,6 +90,7 @@ static DependencyProperty RegisterDp(string propertyName, T? defaultValue, Ac => DependencyProperty.Register(propertyName, typeof(T), typeof(LottieVisualSource), new PropertyMetadata(defaultValue, (d, e) => callback((LottieVisualSource)d, (T)e.OldValue, (T)e.NewValue))); +#endif /// /// Initializes a new instance of the class. @@ -76,6 +99,25 @@ public LottieVisualSource() { } +#if WINAPPSDK + /// + /// Gets or sets options for how the Lottie is loaded. + /// + public LottieVisualOptions Options + { + get => _options; + set => _options = value; + } + + /// + /// Gets or sets the Uniform Resource Identifier (URI) of the JSON source file for this . + /// + public Uri? UriSource + { + get => _uriSource; + set => HandleUriSourcePropertyChanged(_uriSource, value); + } +#else /// /// Gets or sets options for how the Lottie is loaded. /// @@ -93,6 +135,7 @@ public Uri UriSource get => (Uri)GetValue(UriSourceProperty); set => SetValue(UriSourceProperty, value); } +#endif /// /// Called by XAML to convert a string to an . @@ -238,7 +281,7 @@ void NotifyListenersThatCompositionChanged() } // Called when the UriSource property is updated. - void HandleUriSourcePropertyChanged(Uri oldValue, Uri newValue) + void HandleUriSourcePropertyChanged(Uri? oldValue, Uri? newValue) { if (newValue == _uriSource) { @@ -251,6 +294,11 @@ void HandleUriSourcePropertyChanged(Uri oldValue, Uri newValue) _uriSource = newValue; + if (UriSource == null) + { + return; + } + var ignoredTask = StartLoadingAndIgnoreErrorsAsync(); async Task StartLoadingAndIgnoreErrorsAsync() diff --git a/version.json b/version.json index f79db1e6..dc401cbb 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "version": "8.0.230813-rc.{height}", + "version": "8.1.240503-prerelease.{height}", "publicReleaseRefSpec": [ "^refs/heads/main$", // we release out of main "^refs/heads/dev$", // we release out of dev