diff --git a/WinUIGallery/SampleSupport/Data/ControlInfoData.json b/WinUIGallery/SampleSupport/Data/ControlInfoData.json index 681e0569f..feb070d32 100644 --- a/WinUIGallery/SampleSupport/Data/ControlInfoData.json +++ b/WinUIGallery/SampleSupport/Data/ControlInfoData.json @@ -3799,6 +3799,39 @@ } ] }, + { + "UniqueId": "Composition", + "Title": "Composition", + "IconGlyph": "\uE81E", + "Items": [ + { + "UniqueId": "CompositionBasics", + "Title": "Basics", + "ApiNamespace": "Microsoft.UI.Composition", + "Subtitle": "Connect XAML elements to the Visual layer and apply fundamental transforms and clips.", + "ImagePath": "ms-appx:///Assets/ControlImages/AnimationInterop.png", + "Description": "Learn the foundations of XAML and Composition interop by retrieving and attaching visuals, working with coordinate systems, applying transform matrices, and clipping content.", + "IsNew": true, + "Docs": [ + { + "Title": "Composition overview", + "Uri": "https://learn.microsoft.com/windows/apps/windows-app-sdk/composition" + }, + { + "Title": "ElementCompositionPreview - API", + "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.hosting.elementcompositionpreview" + }, + { + "Title": "Visual - API", + "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.composition.visual" + } + ], + "RelatedControls": [ + "XamlCompInterop" + ] + } + ] + }, { "UniqueId": "Motion", "Title": "Motion", diff --git a/WinUIGallery/Samples/CompositionBasics/CompositionBasicsChildVisual.txt b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsChildVisual.txt new file mode 100644 index 000000000..9c4f3ee47 --- /dev/null +++ b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsChildVisual.txt @@ -0,0 +1,33 @@ +--- header +Attach a Composition child Visual and position it with AnchorPoint +--- xaml + +--- c# +private SpriteVisual? _childVisual; + +private void ChildVisualExample_Loaded(object sender, RoutedEventArgs e) +{ + Visual hostVisual = ElementCompositionPreview.GetElementVisual(ChildVisualHost); + _childVisual = hostVisual.Compositor.CreateSpriteVisual(); + _childVisual.Size = new Vector2(80); + _childVisual.Brush = hostVisual.Compositor.CreateColorBrush(Colors.DodgerBlue); + + ElementCompositionPreview.SetElementChildVisual(ChildVisualHost, _childVisual); + UpdateChildVisual(); +} + +private void UpdateChildVisual() +{ + // AnchorPoint is normalized: (0,0) is the top-left and (1,1) is the bottom-right. + _childVisual.AnchorPoint = new Vector2(anchorX, anchorY); + _childVisual.Offset = new Vector3(ChildVisualHost.ActualSize / 2, 0); +} + +private void Page_Unloaded(object sender, RoutedEventArgs e) +{ + ElementCompositionPreview.SetElementChildVisual(ChildVisualHost, null); + _childVisual?.Dispose(); +} diff --git a/WinUIGallery/Samples/CompositionBasics/CompositionBasicsClip.txt b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsClip.txt new file mode 100644 index 000000000..f7defa3e0 --- /dev/null +++ b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsClip.txt @@ -0,0 +1,26 @@ +--- header +Clip a XAML element through its Composition Visual +--- xaml + + + +--- c# +private InsetClip? _insetClip; + +private void ClipExample_Loaded(object sender, RoutedEventArgs e) +{ + Visual visual = ElementCompositionPreview.GetElementVisual(ClipTarget); + _insetClip = visual.Compositor.CreateInsetClip(); + visual.Clip = _insetClip; +} + +private void UpdateClip(float horizontalInset, float verticalInset) +{ + _insetClip.LeftInset = horizontalInset; + _insetClip.RightInset = horizontalInset; + _insetClip.TopInset = verticalInset; + _insetClip.BottomInset = verticalInset; +} diff --git a/WinUIGallery/Samples/CompositionBasics/CompositionBasicsGetElementVisual.txt b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsGetElementVisual.txt new file mode 100644 index 000000000..ea8910e25 --- /dev/null +++ b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsGetElementVisual.txt @@ -0,0 +1,32 @@ +--- header +Get and transform the Visual backing a XAML element +--- xaml + + + +--- c# +private Visual? _elementVisual; + +private void ElementVisualExample_Loaded(object sender, RoutedEventArgs e) +{ + _elementVisual = ElementCompositionPreview.GetElementVisual(ElementVisualTarget); + UpdateVisual(); +} + +private void UpdateVisual() +{ + if (_elementVisual is null) + { + return; + } + + // CenterPoint uses pixels in the Visual's coordinate space. + _elementVisual.CenterPoint = new Vector3(ElementVisualTarget.ActualSize / 2, 0); + // Translation is also exposed directly on UIElement as a Composition facade. + ElementVisualTarget.Translation = new Vector3(translationX, translationY, 0); + _elementVisual.RotationAngleInDegrees = rotation; +} diff --git a/WinUIGallery/Samples/CompositionBasics/CompositionBasicsPage.xaml b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsPage.xaml new file mode 100644 index 000000000..2d2e54f43 --- /dev/null +++ b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsPage.xaml @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WinUIGallery/Samples/CompositionBasics/CompositionBasicsPage.xaml.cs b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsPage.xaml.cs new file mode 100644 index 000000000..1e0499494 --- /dev/null +++ b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsPage.xaml.cs @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.UI.Composition; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Hosting; +using System; +using System.Numerics; + +namespace WinUIGallery.ControlPages; + +public sealed partial class CompositionBasicsPage : Page +{ + private Visual? _elementVisual; + private SpriteVisual? _childVisual; + private Visual? _transformMatrixVisual; + private InsetClip? _insetClip; + + public CompositionBasicsPage() + { + InitializeComponent(); + Unloaded += CompositionBasicsPage_Unloaded; + } + + private void ElementVisualExample_Loaded(object sender, RoutedEventArgs e) + { + _elementVisual = ElementCompositionPreview.GetElementVisual(ElementVisualTarget); + UpdateElementVisualCenterPoint(); + UpdateElementVisualTransform(); + } + + private void ElementVisualTarget_SizeChanged(object sender, SizeChangedEventArgs e) + { + UpdateElementVisualCenterPoint(); + } + + private void ElementVisualTransform_ValueChanged(object sender, Microsoft.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e) + { + UpdateElementVisualTransform(); + } + + private void UpdateElementVisualCenterPoint() + { + if (_elementVisual is null) + { + return; + } + + _elementVisual.CenterPoint = new Vector3(ElementVisualTarget.ActualSize / 2, 0); + } + + private void UpdateElementVisualTransform() + { + if (_elementVisual is null) + { + return; + } + + ElementVisualTarget.Translation = new Vector3( + (float)TranslationXSlider.Value, + (float)TranslationYSlider.Value, + 0); + _elementVisual.RotationAngleInDegrees = (float)RotationSlider.Value; + } + + private void ChildVisualExample_Loaded(object sender, RoutedEventArgs e) + { + if (_childVisual is null) + { + Compositor compositor = ElementCompositionPreview.GetElementVisual(ChildVisualHost).Compositor; + _childVisual = compositor.CreateSpriteVisual(); + _childVisual.Size = new Vector2(80); + _childVisual.Brush = compositor.CreateColorBrush(Windows.UI.Color.FromArgb(255, 0, 120, 212)); + ElementCompositionPreview.SetElementChildVisual(ChildVisualHost, _childVisual); + } + + UpdateChildVisual(); + } + + private void ChildVisualHost_SizeChanged(object sender, SizeChangedEventArgs e) + { + UpdateChildVisual(); + } + + private void AnchorPointSlider_ValueChanged(object sender, Microsoft.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e) + { + UpdateChildVisual(); + } + + private void UpdateChildVisual() + { + if (_childVisual is null) + { + return; + } + + _childVisual.AnchorPoint = new Vector2( + (float)AnchorXSlider.Value, + (float)AnchorYSlider.Value); + _childVisual.Offset = new Vector3(ChildVisualHost.ActualSize / 2, 0); + } + + private void TransformMatrixExample_Loaded(object sender, RoutedEventArgs e) + { + _transformMatrixVisual = ElementCompositionPreview.GetElementVisual(TransformMatrixTarget); + UpdateTransformMatrixCenterPoint(); + UpdateTransformMatrix(); + } + + private void TransformMatrixTarget_SizeChanged(object sender, SizeChangedEventArgs e) + { + UpdateTransformMatrixCenterPoint(); + } + + private void TransformMatrixSlider_ValueChanged(object sender, Microsoft.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e) + { + UpdateTransformMatrix(); + } + + private void UpdateTransformMatrixCenterPoint() + { + if (_transformMatrixVisual is null) + { + return; + } + + _transformMatrixVisual.CenterPoint = new Vector3(TransformMatrixTarget.ActualSize / 2, 0); + } + + private void UpdateTransformMatrix() + { + if (_transformMatrixVisual is null) + { + return; + } + + float skewRadians = (float)(SkewXSlider.Value * Math.PI / 180); + Matrix4x4 skewMatrix = Matrix4x4.Identity; + skewMatrix.M21 = MathF.Tan(skewRadians); + _transformMatrixVisual.TransformMatrix = + Matrix4x4.CreateScale((float)ScaleXSlider.Value, 1, 1) * + skewMatrix; + } + + private void ClipExample_Loaded(object sender, RoutedEventArgs e) + { + Visual visual = ElementCompositionPreview.GetElementVisual(ClipTarget); + _insetClip ??= visual.Compositor.CreateInsetClip(); + visual.Clip = _insetClip; + UpdateClip(); + } + + private void ClipSlider_ValueChanged(object sender, Microsoft.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e) + { + UpdateClip(); + } + + private void UpdateClip() + { + if (_insetClip is null) + { + return; + } + + float horizontalInset = (float)HorizontalClipSlider.Value; + float verticalInset = (float)VerticalClipSlider.Value; + _insetClip.LeftInset = horizontalInset; + _insetClip.RightInset = horizontalInset; + _insetClip.TopInset = verticalInset; + _insetClip.BottomInset = verticalInset; + } + + private void CompositionBasicsPage_Unloaded(object sender, RoutedEventArgs e) + { + ElementCompositionPreview.SetElementChildVisual(ChildVisualHost, null); + _childVisual?.Dispose(); + _childVisual = null; + } +} diff --git a/WinUIGallery/Samples/CompositionBasics/CompositionBasicsTransformMatrix.txt b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsTransformMatrix.txt new file mode 100644 index 000000000..2db426032 --- /dev/null +++ b/WinUIGallery/Samples/CompositionBasics/CompositionBasicsTransformMatrix.txt @@ -0,0 +1,25 @@ +--- header +Apply multiple transforms with TransformMatrix +--- xaml + + + +--- c# +private Visual? _visual; + +private void UpdateTransform(float horizontalScale, float skewInDegrees) +{ + _visual ??= ElementCompositionPreview.GetElementVisual(TransformMatrixTarget); + _visual.CenterPoint = new Vector3(TransformMatrixTarget.ActualSize / 2, 0); + + float skewInRadians = skewInDegrees * MathF.PI / 180; + Matrix4x4 skewMatrix = Matrix4x4.Identity; + skewMatrix.M21 = MathF.Tan(skewInRadians); + _visual.TransformMatrix = + Matrix4x4.CreateScale(horizontalScale, 1, 1) * + skewMatrix; +}