/// <inheritdoc/> protected override void WriteCanvasGeometryRoundedRectangleFactory(CodeBuilder builder, CanvasGeometry.RoundedRectangle obj, string typeName, string fieldName) { builder.WriteLine($"var result = {FieldAssignment(fieldName)}CanvasGeometry.CreateRoundedRectangle("); builder.Indent(); builder.WriteLine("null,"); builder.WriteLine($"{Float(obj.X)},"); builder.WriteLine($"{Float(obj.Y)},"); builder.WriteLine($"{Float(obj.W)},"); builder.WriteLine($"{Float(obj.H)},"); builder.WriteLine($"{Float(obj.RadiusX)},"); builder.WriteLine($"{Float(obj.RadiusY)};"); builder.UnIndent(); }
/// <inheritdoc/> protected override void WriteCanvasGeometryCombinationFactory(CodeBuilder builder, CanvasGeometry.Combination obj, string typeName, string fieldName) { builder.WriteLine($"var result = {FieldAssignment(fieldName)}{CallFactoryFor(obj.A)}."); builder.Indent(); builder.WriteLine($"CombineWith({CallFactoryFor(obj.B)},"); if (obj.Matrix.IsIdentity) { builder.WriteLine("Matrix3x2.Identity,"); } else { builder.WriteLine($"{_stringifier.Matrix3x2(obj.Matrix)},"); } builder.WriteLine($"{_stringifier.CanvasGeometryCombine(obj.CombineMode)});"); builder.UnIndent(); }
/// <inheritdoc/> protected override void WriteAnimatedVisualStart( CodeBuilder builder, IAnimatedVisualInfo info) { // Start writing the instantiator. builder.WriteLine($"ref class {info.ClassName} sealed"); builder.Indent(); builder.WriteLine($": public {AnimatedVisualTypeName}"); builder.UnIndent(); builder.OpenScope(); if (info.AnimatedVisualSourceInfo.UsesCanvasEffects || info.AnimatedVisualSourceInfo.UsesCanvasGeometry) { // D2D factory field. builder.WriteLine("ComPtr<ID2D1Factory> _d2dFactory;"); } }
/// <inheritdoc/> protected override void WriteCanvasGeometryGroupFactory(CodeBuilder builder, CanvasGeometry.Group obj, string typeName, string fieldName) { builder.WriteLine($"ComPtr<ID2D1Geometry> geometries[{obj.Geometries.Length}];"); builder.OpenScope(); for (var i = 0; i < obj.Geometries.Length; i++) { var geometry = obj.Geometries[i]; builder.WriteLine($"{CallFactoryFor(geometry)}->GetGeometry(&geometries[{i}]);"); } builder.CloseScope(); builder.WriteLine($"{typeName} result;"); builder.WriteLine("ComPtr<ID2D1GeometryGroup> group;"); builder.WriteLine("FFHR(_d2dFactory->CreateGeometryGroup("); builder.Indent(); builder.WriteLine($"{FilledRegionDetermination(obj.FilledRegionDetermination)},"); builder.WriteLine("geometries[0].GetAddressOf(),"); builder.WriteLine($"{obj.Geometries.Length},"); builder.WriteLine("&group));"); builder.UnIndent(); builder.WriteLine($"result = {FieldAssignment(fieldName)}new GeoSource(group.Get());"); }
/// <inheritdoc/> protected override void WriteCanvasGeometryCombinationFactory(CodeBuilder builder, CanvasGeometry.Combination obj, string typeName, string fieldName) { builder.WriteLine($"{typeName} result;"); builder.WriteLine("ID2D1Geometry *geoA = nullptr, *geoB = nullptr;"); builder.WriteLine($"{CallFactoryFor(obj.A)}->GetGeometry(&geoA);"); builder.WriteLine($"{CallFactoryFor(obj.B)}->GetGeometry(&geoB);"); builder.WriteLine("ComPtr<ID2D1PathGeometry> path;"); builder.WriteLine($"{FailFastWrapper("_d2dFactory->CreatePathGeometry(&path)")};"); builder.WriteLine("ComPtr<ID2D1GeometrySink> sink;"); builder.WriteLine($"{FailFastWrapper("path->Open(&sink)")};"); builder.WriteLine($"FFHR(geoA->CombineWithGeometry("); builder.Indent(); builder.WriteLine($"geoB,"); builder.WriteLine($"{_stringifier.CanvasGeometryCombine(obj.CombineMode)},"); builder.WriteLine($"{_stringifier.Matrix3x2(obj.Matrix)},"); builder.WriteLine($"sink.Get()));"); builder.UnIndent(); builder.WriteLine("geoA->Release();"); builder.WriteLine("geoB->Release();"); builder.WriteLine($"{FailFastWrapper("sink->Close()")};"); builder.WriteLine($"result = {FieldAssignment(fieldName)}new GeoSource(path.Get());"); }
/// <summary> /// Generate the body of the TryCreateAnimatedVisual() method for the composition that contains LoadedImageSurfaces. /// </summary> void WriteTryCreateInstantiatorWithImageLoading(CodeBuilder builder, CodeGenInfo info) { builder.WriteLine("m_isTryCreateAnimatedVisualCalled = true;"); builder.WriteLine(); builder.WriteLine("diagnostics = nullptr;"); builder.WriteLine("if (!IsRuntimeCompatible())"); builder.OpenScope(); builder.WriteLine("return nullptr;"); builder.CloseScope(); builder.WriteLine(); builder.WriteLine("EnsureImageLoadingStarted();"); builder.WriteLine(); builder.WriteLine("if (m_isAnimatedVisualSourceDynamic && m_loadCompleteEventCount != c_loadedImageSurfaceCount)"); builder.OpenScope(); builder.WriteLine("return nullptr;"); builder.CloseScope(); builder.WriteLine("return ref new AnimatedVisual(compositor,"); builder.Indent(); builder.WriteCommaSeparatedLines(info.LoadedImageSurfaceNodes.Select(n => MakeFieldName(n.Name))); builder.UnIndent(); builder.WriteLine(");"); builder.CloseScope(); builder.WriteLine(); }
protected override void WriteThemePropertyImpls(CodeBuilder builder) { var propertyBindings = SourceInfo.SourceMetadata.PropertyBindings; var sourceClassQualifier = $"{S.Namespace(SourceInfo.Namespace)}::{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.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($"{T.CompositionPropertySet} {sourceClassQualifier}EnsureThemeProperties({T.Compositor} compositor)"); builder.OpenScope(); builder.WriteLine($"if ({SourceInfo.ThemePropertiesFieldName} == nullptr)"); builder.OpenScope(); builder.WriteLine($"{SourceInfo.ThemePropertiesFieldName} = compositor{S.Deref}CreatePropertySet();"); // Initialize the values in the property set. foreach (var prop in propertyBindings) { WriteThemePropertyInitialization(builder, SourceInfo.ThemePropertiesFieldName, prop, prop.BindingName); } builder.CloseScope(); builder.WriteLine(); builder.WriteLine($"return {SourceInfo.ThemePropertiesFieldName};"); 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 (IsInterfaceCustom) { builder.WriteLine($"{T.CompositionPropertySet} {sourceClassQualifier}GetThemeProperties({T.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) { if (SourceInfo.GenerateDependencyObject) { // Write the dependency property accessor. builder.WriteLine($"DependencyProperty^ {sourceClassQualifier}{prop.BindingName}Property()"); builder.OpenScope(); builder.WriteLine($"return _{S.CamelCase(prop.BindingName)}Property;"); builder.CloseScope(); builder.WriteLine(); // Write the dependency property change handler. builder.WriteLine($"void {sourceClassQualifier}On{prop.BindingName}Changed(DependencyObject^ d, DependencyPropertyChangedEventArgs^ e)"); builder.OpenScope(); builder.WriteLine($"auto self = ({sourceClassQualifier}^)d;"); builder.WriteLine(); builder.WriteLine("if (self->_themeProperties != nullptr)"); builder.OpenScope(); WriteThemePropertyInitialization(builder, $"self->{SourceInfo.ThemePropertiesFieldName}", prop, "e->NewValue"); builder.CloseScope(); builder.CloseScope(); builder.WriteLine(); // Write the dependency property initializer. builder.WriteLine($"DependencyProperty^ {sourceClassQualifier}_{S.CamelCase(prop.BindingName)}Property ="); builder.Indent(); builder.WriteLine($"DependencyProperty::Register("); builder.Indent(); builder.WriteLine($"{S.String(prop.BindingName)},"); builder.WriteLine($"{TypeName(prop.ExposedType)}::typeid,"); builder.WriteLine($"{sourceClassQualifier}typeid,"); builder.WriteLine($"ref new PropertyMetadata(c_theme{prop.BindingName},"); builder.WriteLine($"ref new PropertyChangedCallback(&{sourceClassQualifier}On{prop.BindingName}Changed)));"); builder.UnIndent(); builder.UnIndent(); builder.WriteLine(); } // Write the getter. builder.WriteLine($"{TypeName(prop.ExposedType)} {sourceClassQualifier}{prop.BindingName}::get()"); builder.OpenScope(); if (SourceInfo.GenerateDependencyObject) { // Get the value from the dependency property. builder.WriteLine($"return ({TypeName(prop.ExposedType)})GetValue(_{S.CamelCase(prop.BindingName)}Property);"); } else { // Get the value from the backing field. builder.WriteLine($"return _theme{prop.BindingName};"); } builder.CloseScope(); builder.WriteLine(); // Write the setter. builder.WriteLine($"void {sourceClassQualifier}{prop.BindingName}::set({TypeName(prop.ExposedType)} value)"); builder.OpenScope(); if (SourceInfo.GenerateDependencyObject) { builder.WriteLine($"SetValue(_{S.CamelCase(prop.BindingName)}Property, value);"); } else { // 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.OpenScope(); WriteThemePropertyInitialization(builder, "_themeProperties", prop); builder.CloseScope(); } builder.CloseScope(); builder.WriteLine(); } }
/// <inheritdoc/> // Called by the base class to write the end of the file (i.e. everything after the body of the Instantiator class). protected override void WriteFileEnd( CodeBuilder builder, CodeGenInfo info) { if (info.UsesCanvasEffects || info.UsesCanvasGeometry) { // Utility method for D2D geometries builder.WriteLine("static IGeometrySource2D^ CanvasGeometryToIGeometrySource2D(CanvasGeometry geo)"); builder.OpenScope(); builder.WriteLine("ComPtr<ABI::Windows::Graphics::IGeometrySource2D> interop = geo.Detach();"); builder.WriteLine("return reinterpret_cast<IGeometrySource2D^>(interop.Get());"); builder.CloseScope(); builder.WriteLine(); // Utility method for fail-fasting on bad HRESULTs from d2d operations builder.WriteLine("static void FFHR(HRESULT hr)"); builder.OpenScope(); builder.WriteLine("if (hr != S_OK)"); builder.OpenScope(); builder.WriteLine("RoFailFastWithErrorContext(hr);"); builder.CloseScope(); builder.CloseScope(); builder.WriteLine(); } // Write the constructor for the instantiator. builder.UnIndent(); builder.WriteLine("public:"); builder.Indent(); builder.WriteLine("AnimatedVisual(Compositor^ compositor)"); // Initializer list. builder.Indent(); builder.WriteLine(": _c(compositor)"); // Instantiate the reusable ExpressionAnimation. builder.WriteLine($", {info.ReusableExpressionAnimationFieldName}(compositor->CreateExpressionAnimation())"); builder.UnIndent(); builder.OpenScope(); if (info.UsesCanvasEffects || info.UsesCanvasGeometry) { builder.WriteLine($"{FailFastWrapper("D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, _d2dFactory.GetAddressOf())")};"); } // Instantiate the root. This will cause the whole Visual tree to be built and animations started. builder.WriteLine("Root();"); builder.CloseScope(); // Write the destructor. This is how CX implements IClosable/IDisposable. builder.WriteLine("virtual ~AnimatedVisual() { }"); // Write the members on IAnimatedVisual. builder.WriteLine(); builder.WriteLine("property TimeSpan Duration"); builder.OpenScope(); builder.WriteLine("virtual TimeSpan get() { return { c_durationTicks }; }"); builder.CloseScope(); builder.WriteLine(); builder.WriteLine("property Visual^ RootVisual"); builder.OpenScope(); builder.WriteLine("virtual Visual^ get() { return _root; }"); builder.CloseScope(); builder.WriteLine(); builder.WriteLine("property float2 Size"); builder.OpenScope(); builder.WriteLine($"virtual float2 get() {{ return {Vector2(info.CompositionDeclaredSize)}; }}"); builder.CloseScope(); builder.WriteLine(); // Close the scope for the instantiator class. builder.UnIndent(); builder.WriteLine("};"); // Close the anonymous namespace. builder.WriteLine("} // end namespace"); builder.WriteLine(); // Generate the method that creates an instance of the composition. builder.WriteLine($"Microsoft::UI::Xaml::Controls::IAnimatedVisual^ AnimatedVisuals::{info.ClassName}::TryCreateAnimatedVisual("); builder.Indent(); builder.WriteLine("Compositor^ compositor,"); builder.WriteLine("Object^* diagnostics)"); builder.UnIndent(); builder.OpenScope(); builder.WriteLine("diagnostics = nullptr;"); builder.WriteLine("if (!IsRuntimeCompatible())"); builder.OpenScope(); builder.WriteLine("return nullptr;"); builder.CloseScope(); builder.WriteLine("return ref new AnimatedVisual(compositor);"); builder.CloseScope(); }
/// <summary> /// Write a class that implements the IDynamicAnimatedVisualSource interface. /// </summary> void WriteIDynamicAnimatedVisualSource(CodeBuilder builder, CodeGenInfo info) { var nodes = info.LoadedImageSurfaceNodes.ToArray(); builder.WriteLine("namespace AnimatedVisuals"); builder.OpenScope(); builder.WriteLine($"sealed class {info.ClassName} : IDynamicAnimatedVisualSource, INotifyPropertyChanged"); builder.OpenScope(); // Declare variables. builder.WriteLine($"{_stringifier.Const(_stringifier.Int32TypeName)} c_loadedImageSurfaceCount = {nodes.Distinct().Count()};"); builder.WriteLine($"{_stringifier.Int32TypeName} _loadCompleteEventCount;"); builder.WriteLine("bool _isAnimatedVisualSourceDynamic = true;"); builder.WriteLine("bool _isTryCreateAnimatedVisualCalled;"); builder.WriteLine("bool _isImageLoadingStarted;"); builder.WriteLine("EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>> _animatedVisualInvalidatedEventTokenTable;"); // Declare the variables to hold the surfaces. foreach (var n in nodes) { builder.WriteLine($"{_stringifier.ReferenceTypeName(n.TypeName)} {n.FieldName};"); } builder.WriteLine(); // Implement the INotifyPropertyChanged.PropertyChanged event. builder.WriteSummaryComment("This implementation of the INotifyPropertyChanged.PropertyChanged event is specific to C# and does not work on WinRT."); builder.WriteLine("public event PropertyChangedEventHandler PropertyChanged;"); builder.WriteLine(); // Implement the AnimatedVisualInvalidated event. WriteAnimatedVisualInvalidatedEvent(builder); // Define properties. builder.WriteSummaryComment("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 declaring the AnimatedVisualSource. Once <see cref=\"TryCreateAnimatedVisual\"/> is called, changes made to this property will be ignored. Default value is true."); builder.WriteLine("public bool IsAnimatedVisualSourceDynamic"); builder.OpenScope(); builder.WriteLine("get { return _isAnimatedVisualSourceDynamic; }"); builder.WriteLine("set"); builder.OpenScope(); builder.WriteLine("if (!_isTryCreateAnimatedVisualCalled && _isAnimatedVisualSourceDynamic != value)"); builder.OpenScope(); builder.WriteLine("_isAnimatedVisualSourceDynamic = value;"); builder.WriteLine("NotifyPropertyChanged(nameof(IsAnimatedVisualSourceDynamic));"); builder.CloseScope(); builder.CloseScope(); builder.CloseScope(); builder.WriteLine(); builder.WriteSummaryComment("Returns true if all images have loaded. To see if the images succeeded to load, see <see cref=\"ImageSuccessfulLoadingProgress\"/>."); builder.WriteLine("public bool IsImageLoadingCompleted { get; private set; }"); builder.WriteLine(); builder.WriteSummaryComment("Represents the progress of the image loading. Returns value between 0 and 1. 0 means none of the images finished loading. 1 means all images finished loading."); builder.WriteLine("public double ImageSuccessfulLoadingProgress { get; private set; }"); builder.WriteLine(); // Generate the method that creates an instance of the animated visual. builder.WriteLine("public IAnimatedVisual TryCreateAnimatedVisual(Compositor compositor, out object diagnostics)"); builder.OpenScope(); builder.WriteLine("_isTryCreateAnimatedVisualCalled = true;"); builder.WriteLine(); builder.WriteLine("diagnostics = null;"); builder.WriteLine("if (!IsRuntimeCompatible())"); builder.OpenScope(); builder.WriteLine("return null;"); builder.CloseScope(); builder.WriteLine(); builder.WriteLine("EnsureImageLoadingStarted();"); builder.WriteLine(); builder.WriteLine("if (_isAnimatedVisualSourceDynamic && _loadCompleteEventCount != c_loadedImageSurfaceCount)"); builder.OpenScope(); builder.WriteLine("return null;"); builder.CloseScope(); builder.WriteLine("return"); builder.Indent(); WriteAnimatedVisualCall(builder, info); builder.UnIndent(); builder.CloseScope(); builder.WriteLine(); // Generate the method that load all the LoadedImageSurfaces. WriteEnsureImageLoadingStarted(builder, info); // Generate the method that handle the LoadCompleted event of the LoadedImageSurface objects. WriteHandleLoadCompleted(builder); // Generate the method that raise the PropertyChanged event. builder.WriteLine("void NotifyPropertyChanged(string name)"); builder.OpenScope(); builder.WriteLine("PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));"); builder.CloseScope(); builder.WriteLine(); // Generate the method that get or create the EventRegistrationTokenTable. builder.WriteLine("EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>> GetAnimatedVisualInvalidatedEventRegistrationTokenTable()"); builder.OpenScope(); builder.WriteLine("return EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>>.GetOrCreateEventRegistrationTokenTable(ref _animatedVisualInvalidatedEventTokenTable);"); builder.CloseScope(); builder.WriteLine(); }