Generate a way to convert between marker names and progress values, a… (#367)

* Generate a way to convert between marker names and progress values, and set bound colors.

To use this without having to cast to a particular class type, use the -AdditionalInterface command line option in LottieGen.

Cppwinrt example:

 LottieGen.exe -inp MyLottieFile -AdditionalInterface MyNamespace.IMyInterface -l cppwinrt

...then in your cppwinrt project, add an IDL file that defines MyNamespace.IMyInterface and declares the methods you want to access, e.g.:

namespace MyNamespace
{
    interface IMyInterface
    {
        Windows.Foundation.Collections.IMapView<String, Double> Markers { get; };

        void SetColorProperty(String propertyName, Windows.UI.Color value);
    };
}

...and finally, reference the interface from your code with an include of "MyNamespace.IMyInterface.h".
This commit is contained in:
Simeon 2020-10-16 12:13:56 -07:00 коммит произвёл GitHub
Родитель 4303fe9654
Коммит 1832ef714b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 476 добавлений и 110 удалений

Просмотреть файл

@ -238,7 +238,7 @@ sealed class CommandLineOptions
result.Languages = languages.Distinct().ToArray();
// Sort any additional interfaces and remove duplicates.
var additionalInterfaces = result._additionalInterfaces.OrderBy(name => name).Distinct();
var additionalInterfaces = result._additionalInterfaces.OrderBy(name => name).Distinct().ToArray();
result._additionalInterfaces.Clear();
result._additionalInterfaces.AddRange(additionalInterfaces);

Просмотреть файл

@ -2,6 +2,8 @@
// 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.Diagnostics;

Просмотреть файл

@ -1133,6 +1133,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.Tools
// If childCount is >1, insert into the parent.
var index = parent.Children.IndexOf(container);
if (index == -1)
{
// Container has already been removed.
continue;
}
var children = container.Children;
// Get the children from the container.

Просмотреть файл

@ -111,6 +111,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.CSharp
}
namespaces.Add("System");
namespaces.Add("System.Collections.Generic");
namespaces.Add("System.Numerics");
// Windows.UI is needed for Color.
@ -142,7 +143,18 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.CSharp
WriteIAnimatedVisualSource(builder);
}
builder.CloseScope();
builder.WriteLine();
WriteFrameToProgressImpl(builder);
builder.WriteLine();
WriteMarkersPropertyImpl(builder);
builder.WriteLine();
WriteSetColorPropertyImpl(builder);
builder.WriteLine();
WriteSetScalarPropertyImpl(builder);
builder.WriteLine();
}
@ -195,7 +207,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.CSharp
{
foreach (var prop in SourceInfo.SourceMetadata.PropertyBindings)
{
builder.WriteComment($"Dependency property for {prop.BindingName}.");
builder.WriteSummaryComment($"Dependency property for {prop.BindingName}.");
builder.WriteLine($"public static readonly DependencyProperty {prop.BindingName}Property =");
builder.Indent();
builder.WriteLine($"DependencyProperty.Register({_s.String(prop.BindingName)}, typeof({ExposedType(prop)}), typeof({SourceInfo.ClassName}),");
@ -218,7 +230,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.CSharp
{
builder.WriteLine($"static void On{prop.BindingName}Changed(DependencyObject d, DependencyPropertyChangedEventArgs args)");
builder.OpenScope();
WriteThemePropertyInitialization(builder, $"(({SourceInfo.ClassName})d)._themeProperties?", prop, $"({ExposedType(prop)})args.NewValue");
WriteThemePropertyInitialization(builder, $"(({SourceInfo.ClassName})d).{SourceInfo.ThemePropertiesFieldName}?", prop, $"({ExposedType(prop)})args.NewValue");
builder.CloseScope();
builder.WriteLine();
}
@ -310,6 +322,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.CSharp
builder.WriteLine("return null;");
}
builder.CloseScope();
}
void WriteThemeMethodsAndFields(CodeBuilder builder)
@ -342,26 +356,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.CSharp
WriteThemeProperties(builder);
}
// The GetThemeProperties method is designed to allow setting of properties when the actual
// type of the IAnimatedVisualSource is not known. It relies on a custom interface that declares
// it, so if we're not generating code for a custom interface, there's no reason to generate
// the method.
if (SourceInfo.IsInterfaceCustom)
{
builder.WriteLine("public CompositionPropertySet GetThemeProperties(Compositor compositor)");
builder.OpenScope();
builder.WriteLine("return EnsureThemeProperties(compositor);");
builder.CloseScope();
builder.WriteLine();
}
if (SourceInfo.SourceMetadata.PropertyBindings.Any(pb => pb.ExposedType == PropertySetValueType.Color))
{
// There's at least one themed color. They will need a helper method to convert to Vector4.
// If we're generating a custom interface then users may want to use GetThemeProperties
// to set a property color, so in that case make the helper method available to them.
var visibility = SourceInfo.IsInterfaceCustom ? "internal " : string.Empty;
builder.WriteLine($"{visibility}static Vector4 ColorAsVector4(Color color) => new Vector4(color.R, color.G, color.B, color.A);");
builder.WriteLine("static Vector4 ColorAsVector4(Color color) => new Vector4(color.R, color.G, color.B, color.A);");
builder.WriteLine();
}
@ -382,7 +380,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.CSharp
}
builder.CloseScope();
builder.WriteLine("return _themeProperties;");
builder.WriteLine($"return {SourceInfo.ThemePropertiesFieldName};");
builder.CloseScope();
builder.WriteLine();
}
@ -553,6 +551,110 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.CSharp
builder.WriteLine("EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>> GetAnimatedVisualInvalidatedEventRegistrationTokenTable()");
builder.OpenScope();
builder.WriteLine("return EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>>.GetOrCreateEventRegistrationTokenTable(ref _animatedVisualInvalidatedEventTokenTable);");
builder.CloseScope();
}
/// <summary>
/// Generates the FrameToProgress(...) implementation.
/// </summary>
void WriteFrameToProgressImpl(CodeBuilder builder)
{
builder.WriteSummaryComment("Converts a frame number to the corresponding progress value.");
builder.WriteLine($"public double FrameToProgress(double frameNumber)");
builder.OpenScope();
builder.WriteLine($"return frameNumber / {_s.Double(SourceInfo.SourceMetadata.LottieMetadata.Duration.Frames)};");
builder.CloseScope();
}
/// <summary>
/// Generates the Markers property implementation.
/// </summary>
void WriteMarkersPropertyImpl(CodeBuilder builder)
{
builder.WriteSummaryComment("Returns a map from marker names to corresponding progress values.");
builder.WriteLine($"public IReadOnlyDictionary<string, double> Markers =>");
builder.Indent();
builder.WriteLine("new Dictionary<string, double>");
builder.OpenScope();
foreach (var marker in SourceInfo.Markers)
{
builder.WriteLine($"{{ {_s.String(marker.Name)}, {_s.Double(marker.StartProgress)} }},");
}
builder.CloseCppTypeScope();
builder.UnIndent();
}
/// <summary>
/// Generates the SetColorProperty(...) method implementation.
/// </summary>
void WriteSetColorPropertyImpl(CodeBuilder builder) =>
WriteSetPropertyImpl(
builder,
PropertySetValueType.Color,
"Color",
"Sets the color property with the given name, or does nothing if no such property exists.");
/// <summary>
/// Generates the SetScalarProperty(...) method implementation.
/// </summary>
void WriteSetScalarPropertyImpl(CodeBuilder builder) =>
WriteSetPropertyImpl(
builder,
PropertySetValueType.Scalar,
"double",
"Sets the scalar property with the given name, or does nothing if no such property exists.");
void WriteSetPropertyImpl(
CodeBuilder builder,
PropertySetValueType propertyType,
string typeName,
string comment)
{
builder.WriteSummaryComment(comment);
var properties = SourceInfo.SourceMetadata.PropertyBindings.Where(p => p.ExposedType == propertyType).ToArray();
builder.WriteLine($"public void Set{propertyType}Property(string propertyName, {typeName} value)");
if (properties.Length == 0)
{
// There are no properties. The method doesn't need to do anything.
builder.OpenScope();
builder.CloseScope();
}
else
{
var propertySetTypeName = PropertySetValueTypeName(properties[0].ActualType);
var valueInitializer = properties[0].ExposedType == PropertySetValueType.Color ? "ColorAsVector4(value)" : "value";
builder.OpenScope();
var firstSeen = false;
foreach (var prop in properties)
{
// If the propertyName is a known name, save it into its backing field.
builder.WriteLine($"{(firstSeen ? "else " : string.Empty)}if (propertyName == {_s.String(prop.BindingName)})");
firstSeen = true;
builder.OpenScope();
builder.WriteLine($"_theme{prop.BindingName} = value;");
builder.CloseScope();
}
builder.WriteLine("else");
builder.OpenScope();
// Ignore the name if it doesn't refer to a known property.
builder.WriteLine("return;");
builder.CloseScope();
builder.WriteLine();
// Update the CompositionPropertySet if it has been created.
builder.WriteLine($"if ({SourceInfo.ThemePropertiesFieldName} != null)");
builder.OpenScope();
builder.WriteLine($"{SourceInfo.ThemePropertiesFieldName}.Insert{propertySetTypeName}(propertyName, {valueInitializer});");
builder.CloseScope();
builder.CloseScope();
}
}
/// <inheritdoc/>

Просмотреть файл

@ -112,20 +112,20 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
{
var builder = new CodeBuilder();
builder.WriteLine(string.Join("\r\n", AutoGeneratedHeaderText));
var imports = new List<string>();
var idlImports = new List<string>();
if (SourceInfo.IsInterfaceCustom)
{
imports.Add($"import \"{SourceInfo.InterfaceType.NormalizedQualifiedName}.idl\";");
idlImports.Add(SourceInfo.InterfaceType.NormalizedQualifiedName);
}
imports.AddRange(SourceInfo.AdditionalInterfaces.Select(n => n.GetQualifiedName(_s)));
idlImports.AddRange(SourceInfo.AdditionalInterfaces.Select(n => n.NormalizedQualifiedName));
if (imports.Any())
if (idlImports.Any())
{
foreach (var import in imports)
foreach (var import in idlImports)
{
builder.WriteLine(import);
builder.WriteLine($"import \"{import}.idl\";");
}
builder.WriteLine();
@ -161,7 +161,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
builder.WriteLine(", Windows.UI.Xaml.Data.INotifyPropertyChanged");
}
foreach (var additionalInterface in SourceInfo.AdditionalInterfaces)
foreach (var additionalInterface in SourceInfo.AdditionalInterfaces.Select(n => n.NormalizedQualifiedName))
{
builder.WriteLine($", {additionalInterface}");
}
@ -230,9 +230,29 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
{
WriteIDynamicAnimatedVisualSourceHeaderText(builder);
}
else
WriteTryCreateAnimatedVisualDecl(builder.Class.Public);
builder.Class.Public.WriteLine();
WriteFrameToProgressDecl(builder.Class.Public);
builder.Class.Public.WriteLine();
WriteMarkersPropertyDecl(builder.Class.Public);
builder.Class.Public.WriteLine();
WriteSetColorPropertyDecl(builder.Class.Public);
builder.Class.Public.WriteLine();
WriteSetScalarPropertyDecl(builder.Class.Public);
if (SourceInfo.IsThemed)
{
WriteIAnimatedVisualSourceHeaderText(builder);
builder.Class.Private.WriteLine();
builder.Class.Private.WriteLine($"static winrt::Windows::Foundation::Numerics::float4 ColorAsVector4(winrt::Windows::UI::Color color);");
}
// Close the ::implementation namespace.
@ -292,7 +312,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
void WriteSourceDescriptionComments(CodeBuilder builder) =>
builder.WritePreformattedCommentLines(GetSourceDescriptionLines());
void WriteTryCreateAnimatedVisualDeclaration(CodeBuilder builder)
void WriteTryCreateAnimatedVisualDecl(CodeBuilder builder)
{
builder.WriteLine($"winrt::{_animatedVisualTypeName} TryCreateAnimatedVisual(");
builder.Indent();
@ -301,22 +321,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
builder.UnIndent();
}
void WriteIAnimatedVisualSourceHeaderText(HeaderBuilder builder)
{
WriteTryCreateAnimatedVisualDeclaration(builder.Class.Public);
if (SourceInfo.IsThemed)
{
// The GetThemeProperties method is designed to allow setting of properties when the actual
// type of the IAnimatedVisualSource is not known.
builder.Class.Public.WriteLine();
builder.Class.Public.WriteLine($"winrt::{_wuc}::CompositionPropertySet GetThemeProperties(winrt::{_wuc}::Compositor compositor);");
builder.Class.Public.WriteLine();
builder.Class.Public.WriteLine($"static winrt::Windows::Foundation::Numerics::float4 ColorAsVector4(winrt::Windows::UI::Color color);");
}
}
void WriteThemeHeader(HeaderBuilder builder)
{
// Add a field to hold the theme property set.
@ -348,7 +352,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
}
}
// EnsureThemeProperties is private. GetThemeProperties is the public version.
// EnsureThemeProperties is private.
builder.Class.Private.WriteLine($"winrt::{_wuc}::CompositionPropertySet EnsureThemeProperties(winrt::{_wuc}::Compositor compositor);");
// Write properties declarations for each themed property.
@ -366,19 +370,17 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
{
var propertyBindings = SourceInfo.SourceMetadata.PropertyBindings;
var sourceClassQualifier = $"{_sourceClassName}::";
if (propertyBindings.Any(pb => pb.ExposedType == PropertySetValueType.Color))
{
// Write the helper for converting a color to a vector 4.
builder.WriteLine($"float4 {sourceClassQualifier}ColorAsVector4(Color color)");
builder.WriteLine($"float4 {_sourceClassName}::ColorAsVector4(Color color)");
builder.OpenScope();
builder.WriteLine("return { static_cast<float>(color.R), static_cast<float>(color.G), static_cast<float>(color.B), static_cast<float>(color.A) };");
builder.CloseScope();
builder.WriteLine();
}
builder.WriteLine($"CompositionPropertySet {sourceClassQualifier}EnsureThemeProperties(Compositor compositor)");
builder.WriteLine($"CompositionPropertySet {_sourceClassName}::EnsureThemeProperties(Compositor compositor)");
builder.OpenScope();
builder.WriteLine($"if ({SourceInfo.ThemePropertiesFieldName} == nullptr)");
builder.OpenScope();
@ -396,17 +398,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
builder.CloseScope();
builder.WriteLine();
builder.WriteLine($"CompositionPropertySet {sourceClassQualifier}GetThemeProperties(Compositor compositor)");
builder.OpenScope();
builder.WriteLine("return EnsureThemeProperties(compositor);");
builder.CloseScope();
builder.WriteLine();
// Write property implementations for each theme property.
foreach (var prop in propertyBindings)
{
// Write the getter. This just reads the values out of the backing field.
builder.WriteLine($"{TypeName(prop.ExposedType)} {sourceClassQualifier}{prop.BindingName}()");
builder.WriteLine($"{TypeName(prop.ExposedType)} {_sourceClassName}::{prop.BindingName}()");
builder.OpenScope();
builder.WriteLine($"return _theme{prop.BindingName};");
builder.CloseScope();
@ -414,12 +410,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
// Write the setter. This saves to the backing field, and updates the theme property
// set if one has been created.
builder.WriteLine($"void {sourceClassQualifier}{prop.BindingName}({TypeName(prop.ExposedType)} value)");
builder.WriteLine($"void {_sourceClassName}::{prop.BindingName}({TypeName(prop.ExposedType)} value)");
builder.OpenScope();
builder.WriteLine($"_theme{prop.BindingName} = value;");
builder.WriteLine("if (_themeProperties != nullptr)");
builder.WriteLine($"if ({SourceInfo.ThemePropertiesFieldName} != nullptr)");
builder.OpenScope();
WriteThemePropertyInitialization(builder, "_themeProperties", prop);
WriteThemePropertyInitialization(builder, SourceInfo.ThemePropertiesFieldName, prop);
builder.CloseScope();
builder.CloseScope();
builder.WriteLine();
@ -481,8 +477,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
pub.WriteSummaryComment("Returns true if all images have finished loading.");
pub.WriteLine("bool IsImageLoadingCompleted();");
pub.WriteLine();
WriteTryCreateAnimatedVisualDeclaration(builder.Class.Public);
}
/// <inheritdoc/>
@ -553,10 +547,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
builder.WriteLine("#include \"pch.h\"");
builder.WriteLine($"#include \"{_headerFileName}\"");
builder.WriteLine($"#include \"{_cppwinrtGeneratedFileNameBase}.cpp\"");
// floatY, floatYxZ
builder.WriteLine("#include <WindowsNumerics.h>");
builder.WriteLine("#include <winrt/Windows.Foundation.Metadata.h>");
if (SourceInfo.WinUi3)
@ -799,11 +789,146 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
WriteIAnimatedVisualSource(builder);
}
builder.WriteLine();
WriteFrameToProgressImpl(builder);
builder.WriteLine();
WriteMarkersPropertyImpl(builder);
builder.WriteLine();
WriteSetColorPropertyImpl(builder);
builder.WriteLine();
WriteSetScalarPropertyImpl(builder);
// Close the namespace.
builder.UnIndent();
builder.WriteLine("} // end namespace");
}
/// <summary>
/// Generates the FrameToProgress(...) declaration.
/// </summary>
void WriteFrameToProgressDecl(CodeBuilder builder)
{
builder.WriteComment("Converts a frame number to the corresponding progress value.");
builder.WriteLine($"double FrameToProgress(double frameNumber);");
}
/// <summary>
/// Generates the FrameToProgress(...) implementation.
/// </summary>
void WriteFrameToProgressImpl(CodeBuilder builder)
{
builder.WriteLine($"double {_sourceClassName}::FrameToProgress(double frameNumber)");
builder.OpenScope();
builder.WriteLine($"return frameNumber / {_s.Double(SourceInfo.SourceMetadata.LottieMetadata.Duration.Frames)};");
builder.CloseScope();
}
/// <summary>
/// Generates the Markers property declaration.
/// </summary>
void WriteMarkersPropertyDecl(CodeBuilder builder)
{
builder.WriteComment("Returns a map from marker names to corresponding progress values.");
builder.WriteLine("winrt::Windows::Foundation::Collections::IMapView<hstring, double> Markers();");
}
/// <summary>
/// Generates the Markers property implementation.
/// </summary>
void WriteMarkersPropertyImpl(CodeBuilder builder)
{
builder.WriteLine($"winrt::Windows::Foundation::Collections::IMapView<hstring, double> {_sourceClassName}::Markers()");
builder.OpenScope();
builder.WriteLine("return winrt::single_threaded_map<winrt::hstring, double>(");
builder.Indent();
builder.WriteLine("std::map<winrt::hstring, double>");
builder.OpenScope();
foreach (var marker in SourceInfo.Markers)
{
builder.WriteLine($"{{ {_s.String(marker.Name)}, {_s.Double(marker.StartProgress)} }},");
}
builder.CloseScope();
builder.UnIndent();
builder.WriteLine(").GetView();");
builder.CloseScope();
}
void WriteSetColorPropertyDecl(CodeBuilder builder)
{
builder.WriteComment("Sets the color property with the given name, or does nothing if no such property exists.");
builder.WriteLine("void SetColorProperty(hstring const& propertyName, winrt::Windows::UI::Color value);");
}
void WriteSetScalarPropertyDecl(CodeBuilder builder)
{
builder.WriteComment("Sets the scalar property with the given name, or does nothing if no such property exists.");
builder.WriteLine("void SetScalarProperty(hstring const& propertyName, double value);");
}
void WriteSetColorPropertyImpl(CodeBuilder builder) =>
WriteSetPropertyImpl(builder, PropertySetValueType.Color, "Color");
void WriteSetScalarPropertyImpl(CodeBuilder builder) =>
WriteSetPropertyImpl(builder, PropertySetValueType.Scalar, "double");
void WriteSetPropertyImpl(CodeBuilder builder, PropertySetValueType propertyType, string typeName)
{
var properties = SourceInfo.SourceMetadata.PropertyBindings.Where(p => p.ExposedType == propertyType).ToArray();
if (properties.Length == 0)
{
// There are no properties. The method doesn't need to do anything.
builder.WriteLine($"void {_sourceClassName}::Set{propertyType}Property(hstring const&, {typeName})");
builder.OpenScope();
builder.CloseScope();
}
else
{
var propertySetTypeName = PropertySetValueTypeName(properties[0].ActualType);
var valueInitializer = properties[0].ExposedType == PropertySetValueType.Color ? "ColorAsVector4(value)" : "value";
builder.WriteLine($"void {_sourceClassName}::Set{propertyType}Property(hstring const& propertyName, {typeName} value)");
builder.OpenScope();
var firstSeen = false;
foreach (var prop in properties)
{
// If the propertyName is a known name, save it into its backing field.
builder.WriteLine($"{(firstSeen ? "else " : string.Empty)}if (propertyName == {_s.String(prop.BindingName)})");
firstSeen = true;
builder.OpenScope();
builder.WriteLine($"_theme{prop.BindingName} = value;");
builder.CloseScope();
}
builder.WriteLine("else");
builder.OpenScope();
// Ignore the name if it doesn't refer to a known property.
builder.WriteLine("return;");
builder.CloseScope();
builder.WriteLine();
// Update the CompositionPropertySet if it has been created.
builder.WriteLine($"if ({SourceInfo.ThemePropertiesFieldName} != nullptr)");
builder.OpenScope();
builder.WriteLine($"{SourceInfo.ThemePropertiesFieldName}.Insert{propertySetTypeName}(propertyName, {valueInitializer});");
builder.CloseScope();
builder.CloseScope();
}
}
/// <summary>
/// Generate the body of the TryCreateAnimatedVisual() method for a composition that does not contain LoadedImageSurfaces.
/// </summary>

Просмотреть файл

@ -49,7 +49,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cppwinrt
public override string Double(double value) =>
Math.Floor(value) == value
? value.ToString("0.0", CultureInfo.InvariantCulture) + "d"
? value.ToString("0.0", CultureInfo.InvariantCulture)
: value.ToString("G15", CultureInfo.InvariantCulture);
public override string FilledRegionDetermination(Mgcg.CanvasFilledRegionDetermination value) =>

Просмотреть файл

@ -149,20 +149,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cx
builder.Public.Indent();
builder.Public.WriteLine($"{_wuc}::Compositor^ compositor,");
builder.Public.WriteLine($"Object^* diagnostics);");
// The GetThemeProperties method is designed to allow setting of properties when the actual
// type of the IAnimatedVisualSource is not known. It relies on a custom interface that declares
// it, so if we're not generating code for a custom interface, there's no reason to generate
// the method.
if (SourceInfo.IsInterfaceCustom && SourceInfo.IsThemed)
{
var optionalVirtual = SourceInfo.InterfaceType is null ? string.Empty : "virtual ";
builder.Public.WriteLine($"{optionalVirtual}{_wuc}::CompositionPropertySet^ GetThemeProperties({_wuc}::Compositor^ compositor);");
builder.Public.WriteLine();
}
builder.Public.UnIndent();
builder.Public.WriteLine();
WriteMarkersPropertyDecl(builder.Public);
builder.Public.WriteLine();
WriteSetColorPropertyDecl(builder.Public);
builder.Public.WriteLine();
WriteSetScalarPropertyDecl(builder.Public);
}
void WriteHeaderClassStart(CodeBuilder builder, IReadOnlyList<string> inherits)
@ -261,19 +257,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cx
builder.CloseScope();
builder.WriteLine();
// The GetThemeProperties method is designed to allow setting of properties when the actual
// type of the IAnimatedVisualSource is not known. It relies on a custom interface that declares
// it, so if we're not generating code for a custom interface, there's no reason to generate
// the method.
if (SourceInfo.IsInterfaceCustom)
{
builder.WriteLine($"CompositionPropertySet^ {sourceClassQualifier}GetThemeProperties(Compositor^ compositor)");
builder.OpenScope();
builder.WriteLine("return EnsureThemeProperties(compositor);");
builder.CloseScope();
builder.WriteLine();
}
// Write property implementations for each theme property.
foreach (var prop in propertyBindings)
{
@ -291,7 +274,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cx
builder.OpenScope();
builder.WriteLine($"auto self = ({sourceClassQualifier}^)d;");
builder.WriteLine();
builder.WriteLine("if (self->_themeProperties != nullptr)");
builder.WriteLine($"if (self->{SourceInfo.ThemePropertiesFieldName} != nullptr)");
builder.OpenScope();
WriteThemePropertyInitialization(builder, $"self->{SourceInfo.ThemePropertiesFieldName}", prop, "e->NewValue");
builder.CloseScope();
@ -342,9 +325,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cx
// This saves to the backing field, and updates the theme property
// set if one has been created.
builder.WriteLine($"_theme{prop.BindingName} = value;");
builder.WriteLine("if (_themeProperties != nullptr)");
builder.WriteLine($"if ({SourceInfo.ThemePropertiesFieldName} != nullptr)");
builder.OpenScope();
WriteThemePropertyInitialization(builder, "_themeProperties", prop);
WriteThemePropertyInitialization(builder, SourceInfo.ThemePropertiesFieldName, prop);
builder.CloseScope();
}
@ -399,10 +382,17 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cx
pub.WriteLine($"Object^* diagnostics);");
pub.UnIndent();
pub.WriteLine();
WriteFrameToProgressDecl(pub);
pub.WriteLine();
WriteMarkersPropertyDecl(pub);
pub.WriteLine();
pub.WriteLine($"virtual event PropertyChangedEventHandler^ PropertyChanged;");
pub.WriteLine();
pub.WriteSummaryComment("If this property is set to true, <see cref=\"TryCreateAnimatedVisual\"/> will" +
pub.WriteComment("If this property is set to true, <see cref=\"TryCreateAnimatedVisual\"/> will" +
" return null until all images have loaded. When all images have loaded, <see cref=\"TryCreateAnimatedVisual\"/>" +
" will return the AnimatedVisual. To use, set it when instantiating the AnimatedVisualSource. Once" +
" <see cref=\"TryCreateAnimatedVisual\"/> is called, changes made to this property will be ignored." +
@ -414,7 +404,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cx
pub.CloseScope();
pub.WriteLine();
pub.WriteSummaryComment("Returns true if all images have finished loading.");
pub.WriteComment("Returns true if all images have finished loading.");
pub.WriteLine("property bool IsImageLoadingCompleted");
pub.OpenScope();
pub.WriteLine("bool get() { return m_isImageLoadingCompleted; }");
@ -669,6 +659,139 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Cx
{
WriteIAnimatedVisualSource(builder);
}
builder.WriteLine();
WriteFrameToProgressImpl(builder);
builder.WriteLine();
WriteMarkersPropertyImpl(builder);
builder.WriteLine();
WriteSetColorPropertyImpl(builder);
builder.WriteLine();
WriteSetScalarPropertyImpl(builder);
}
/// <summary>
/// Generates the FrameToProgress(...) declaration.
/// </summary>
void WriteFrameToProgressDecl(CodeBuilder builder)
{
builder.WriteComment("Converts a frame number to the corresponding progress value.");
builder.WriteLine($"double FrameToProgress(double frameNumber);");
}
/// <summary>
/// Generates the FrameToProgress(...) implementation.
/// </summary>
void WriteFrameToProgressImpl(CodeBuilder builder)
{
builder.WriteLine($"double {_s.Namespace(SourceInfo.Namespace)}::{_sourceClassName}::FrameToProgress(double frameNumber);");
builder.OpenScope();
builder.WriteLine($"return frameNumber / {_s.Double(SourceInfo.SourceMetadata.LottieMetadata.Duration.Frames)}");
builder.CloseScope();
}
/// <summary>
/// Generates the GetMarkerAsProgress(...) declaration.
/// </summary>
void WriteMarkersPropertyDecl(CodeBuilder builder)
{
builder.WriteComment("Returns a map from marker names to corresponding progress values.");
builder.WriteLine($"property Windows::Foundation::Collections::IMapView<Platform::String^, double>");
builder.OpenScope();
builder.WriteLine("Windows::Foundation::Collections::IMapView<Platform::String^, double> get();");
builder.CloseScope();
}
/// <summary>
/// Generates the GetMarkerAsProgress(...) implementation.
/// </summary>
void WriteMarkersPropertyImpl(CodeBuilder builder)
{
builder.WriteLine($"Windows::Foundation::Collections::IMapView<String^, double> {_s.Namespace(SourceInfo.Namespace)}::{_sourceClassName}::Markers::get()");
builder.OpenScope();
builder.WriteLine("return ref new Platforms::Collections::Map<String^, double>(");
builder.Indent();
builder.OpenScope();
foreach (var marker in SourceInfo.Markers)
{
builder.WriteLine($"{{ {_s.String(marker.Name)}, {_s.Double(marker.StartProgress)} }},");
}
builder.CloseScope();
builder.UnIndent();
builder.WriteLine(").GetView();");
builder.CloseScope();
}
void WriteSetColorPropertyDecl(CodeBuilder builder)
{
builder.WriteComment("Sets the color property with the given name, or does nothing if no such property exists.");
builder.WriteLine("void SetColorProperty(Platform::String^ propertyName, Windows::UI::Color value);");
}
void WriteSetScalarPropertyDecl(CodeBuilder builder)
{
builder.WriteComment("Sets the scalar property with the given name, or does nothing if no such property exists.");
builder.WriteLine("void SetScalarProperty(Platform::String^ propertyName, double value);");
}
void WriteSetColorPropertyImpl(CodeBuilder builder) =>
WriteSetPropertyImpl(builder, PropertySetValueType.Color, "Color");
void WriteSetScalarPropertyImpl(CodeBuilder builder) =>
WriteSetPropertyImpl(builder, PropertySetValueType.Color, "Color");
void WriteSetPropertyImpl(CodeBuilder builder, PropertySetValueType propertyType, string typeName)
{
var properties = SourceInfo.SourceMetadata.PropertyBindings.Where(p => p.ExposedType == propertyType).ToArray();
if (properties.Length == 0)
{
// There are no properties. The method doesn't need to do anything.
builder.WriteLine($"void {_s.Namespace(SourceInfo.Namespace)}::{_sourceClassName}::Set{propertyType}Property(String^, {typeName})");
builder.OpenScope();
builder.CloseScope();
}
else
{
var propertySetTypeName = PropertySetValueTypeName(properties[0].ActualType);
var valueInitializer = properties[0].ExposedType == PropertySetValueType.Color ? "ColorAsVector4(value)" : "value";
builder.WriteLine($"void {_sourceClassName}::Set{propertyType}Property(String^ propertyName, {typeName} value)");
builder.OpenScope();
var firstSeen = false;
foreach (var prop in properties)
{
// If the propertyName is a known name, save it into its backing field.
builder.WriteLine($"{(firstSeen ? "else " : string.Empty)}if (propertyName == {_s.String(prop.BindingName)})");
firstSeen = true;
builder.OpenScope();
builder.WriteLine($"_theme{prop.BindingName} = value;");
builder.CloseScope();
}
builder.WriteLine("else");
builder.OpenScope();
// Ignore the name if it doesn't refer to a known property.
builder.WriteLine("return;");
builder.CloseScope();
builder.WriteLine();
// Update the CompositionPropertySet if it has been created.
builder.WriteLine($"if ({SourceInfo.ThemePropertiesFieldName} != nullptr)");
builder.OpenScope();
builder.WriteLine($"{SourceInfo.ThemePropertiesFieldName}.Insert{propertySetTypeName}(propertyName, {valueInitializer});");
builder.CloseScope();
builder.CloseScope();
}
}
/// <summary>

Просмотреть файл

@ -123,9 +123,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen
/// </summary>
IReadOnlyList<NamedConstant> InternalConstants { get; }
/// <summary>
/// The markers. These are names for progress values.
/// </summary>
IReadOnlyList<MarkerInfo> Markers { get; }
/// <summary>
/// Accesses metadata associated with the source of the composition. This may contain
/// information such as the frame rate and markers from the source. The contents of
/// information such as the frame rate and theme bindings from the source. The contents of
/// this data is source specific.
/// </summary>
SourceMetadata SourceMetadata { get; }

Просмотреть файл

@ -5,11 +5,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks.Dataflow;
using Microsoft.Toolkit.Uwp.UI.Lottie.CompMetadata;
using Microsoft.Toolkit.Uwp.UI.Lottie.GenericData;
using Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen.Tables;
@ -60,7 +58,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen
readonly TypeName _interfaceType;
readonly IReadOnlyList<TypeName> _additionalInterfaces;
readonly bool _isInterfaceCustom;
readonly IReadOnlyList<MarkerInfo> _lottieMarkers;
readonly IReadOnlyList<MarkerInfo> _markers;
readonly IReadOnlyList<NamedConstant> _internalConstants;
AnimatedVisualGenerator? _currentAnimatedVisualGenerator;
@ -85,7 +83,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen
_interfaceType = new TypeName(configuration.InterfaceType);
_isInterfaceCustom = _interfaceType.NormalizedQualifiedName != "Microsoft.UI.Xaml.Controls.IAnimatedVisual";
_additionalInterfaces = configuration.AdditionalInterfaces.Select(n => new TypeName(n)).ToArray();
_lottieMarkers = MarkerInfo.GetMarkerInfos(_sourceMetadata.LottieMetadata.FilteredMarkers).ToArray();
_markers = MarkerInfo.GetMarkerInfos(_sourceMetadata.LottieMetadata.FilteredMarkers).ToArray();
_internalConstants = GetInternalConstants().ToArray();
var graphs = configuration.ObjectGraphs;
@ -397,7 +395,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen
_compositionDuration.Ticks);
// Get the markers.
foreach (var marker in _lottieMarkers)
foreach (var marker in _markers)
{
yield return new NamedConstant(marker.StartConstant, $"Marker: {marker.Name}.", ConstantType.Float, (float)marker.StartProgress);
if (marker.DurationInFrames > 0)
@ -448,9 +446,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen
yield return $"Frame count: {metadata.Duration.Frames}";
yield return $"Duration: {metadata.Duration.Time.TotalMilliseconds:0.0} mS";
if (_lottieMarkers.Count > 0)
if (_markers.Count > 0)
{
foreach (var line in LottieMarkersMonospaceTableFormatter.GetMarkersDescriptionLines(_s, _lottieMarkers))
foreach (var line in LottieMarkersMonospaceTableFormatter.GetMarkersDescriptionLines(_s, _markers))
{
yield return line;
}
@ -761,6 +759,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen
bool IAnimatedVisualSourceInfo.UsesCompositeEffect => _animatedVisualGenerators.Any(f => f.UsesCompositeEffect);
IReadOnlyList<MarkerInfo> IAnimatedVisualSourceInfo.Markers => _markers;
IReadOnlyList<NamedConstant> IAnimatedVisualSourceInfo.InternalConstants => _internalConstants;
IReadOnlyList<LoadedImageSurfaceInfo> IAnimatedVisualSourceInfo.LoadedImageSurfaces => _loadedImageSurfaceInfos;
@ -945,7 +945,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen
static IEnumerable<ObjectData> OrderByTypeThenName(IEnumerable<ObjectData> nodes) =>
nodes.OrderBy(n => n.TypeName).ThenBy(n => n.Name, AlphanumericStringComparer.Instance);
static string PropertySetValueTypeName(PropertySetValueType value)
private protected static string PropertySetValueTypeName(PropertySetValueType value)
=> value switch
{
PropertySetValueType.Color => "Color",

Просмотреть файл

@ -13,6 +13,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen
/// Information about a marker. Markers refer to points in time or segments of time in
/// an animation.
/// </summary>
#if PUBLIC_UIDataCodeGen
public
#endif
sealed class MarkerInfo
{
readonly Marker _marker;