diff --git a/README.md b/README.md index d0bcf46..6c3808f 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ The package exposes synchronous and asynchronous APIs (from the `CompositionExte The library also has APIs to automatically combine different kinds of animations, like Fade + Slide or Fade + Scale, and various helper methods to change UI-related parameters of a target object. Here are some animation exaples: #### Synchronous fade animation + ```C# MyControl.StartCompositionFadeAnimation( null, // Using null will make the fade animation start from the current value @@ -57,6 +58,7 @@ MyControl.StartCompositionFadeAnimation( ``` #### Asynchronous fade and scale animation + ```C# await MyControl.StartCompositionFadeScaleAnimationAsync( null, // Initial opacity (use current value) @@ -95,11 +97,13 @@ The library provides several ways to use `UI.Composition` effects. There are rea **Note**: the `NoiseTextureUri` parameter must be set to a .png image with a noise texture. It is up to the developer to create his own noise texture and to import it into the app. An easy plugin to create one is [NoiseChoice](https://forums.getpaint.net/topic/22500-red-ochre-plug-in-pack-v9-updated-30th-july-2014/) for [Paint.NET](https://www.getpaint.net/). #### Create and assign an acrylic brush in C# + ```C# control.Background = CompositionBrushBuilder.FromHostBackdropAcrylic(Colors.DarkOrange, 0.6f, new Uri("ms-appx:///Assets/noise.png")).AsBrush(); ``` #### Build an acrylic effect pipeline from scratch: + ```C# Brush brush = CompositionBrushBuilder.FromHostBackdropBrush() .Effect(source => new LuminanceToAlphaEffect { Source = source }) @@ -113,6 +117,7 @@ Brush brush = CompositionBrushBuilder.FromHostBackdropBrush() The `CompositionBrushBuilder` class can also be used to quickly implement custom XAML brushes with an arbitrary effects pipeline. To do so, just inherit from `XamlCompositionEffectBrushBase` and setup your own effects pipeline in the `OnBrushRequested` method. #### Get a custom effect that can be animated: + ```C# // Build the effects pipeline XamlCompositionBrush acrylic = CompositionBrushBuilder.FromHostBackdropAcrylic(Colors.Orange, 0.6f, new Uri("ms-appx:///Assets/noise.png")) @@ -124,6 +129,34 @@ acrylic.Bind(animation, out XamlEffectAnimation saturation); // Bind the effect saturation(0.2f, 250); // Animate the opacity to 0.2 in 250ms ``` +#### Create custom effects in XAML: + +Using the APIs in `UICompositionAnimations.Behaviours.Xaml` it is also possible to build complex Composition/Win2D pipelines directly from XAML, in a declarative way. This is how to define a custom host backdrop acrylic brush: + +```xml +xmlns:xaml="using:UICompositionAnimations.Behaviours.Xaml" +xmlns:effects="using:UICompositionAnimations.Behaviours.Xaml.Effects" + + + + + + + + + + + + + + + + + + + +``` + ## Reveal highlight effect Part of the Fluent Design System introduced with Windows 10 Fall Creators Update, this effect can actually already be used with Windows 10 Creators Update (build 15063.x). The library exposes APIs to easily use the effect in an application. @@ -145,6 +178,7 @@ LightsSourceHelper.SetIsLightsContainer(Window.Current.Content, true); // Assign ``` #### Setup the target brushes for the lights + ````XAML ```` + ```C# // Since the second light has a special ID, it is necessary to manually set its target brush LightingBrush brush = Application.Current.Resources["BorderWideLightBrush"] as LightingBrush; diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/Abstract/ImageEffectBase.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/Abstract/ImageEffectBase.cs new file mode 100644 index 0000000..381ada6 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/Abstract/ImageEffectBase.cs @@ -0,0 +1,26 @@ +using System; +using UICompositionAnimations.Enums; + +namespace UICompositionAnimations.Behaviours.Xaml.Effects.Abstract +{ + /// + /// An image based effect that loads an image at the specified location + /// + public abstract class ImageEffectBase : IPipelineEffect + { + /// + /// Gets or sets the for the image to load + /// + public Uri Uri { get; set; } + + /// + /// Gets or sets the DPI mode used to render the image (the default is ) + /// + public BitmapDPIMode DPIMode { get; set; } = BitmapDPIMode.CopyDisplayDPISettingsWith96AsLowerBound; + + /// + /// Gets or sets the cache mode to use when loading the image (the default is ) + /// + public BitmapCacheMode CacheMode { get; set; } = BitmapCacheMode.Default; + } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/Abstract/ValueEffectBase.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/Abstract/ValueEffectBase.cs new file mode 100644 index 0000000..63bfba1 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/Abstract/ValueEffectBase.cs @@ -0,0 +1,13 @@ +namespace UICompositionAnimations.Behaviours.Xaml.Effects.Abstract +{ + /// + /// A base for an effect that exposes a single parameter + /// + public abstract class ValueEffectBase : IPipelineEffect + { + /// + /// Gets or sets the value of the parameter for the current effect + /// + public double Value { get; set; } + } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/BackdropEffect.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/BackdropEffect.cs new file mode 100644 index 0000000..f614801 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/BackdropEffect.cs @@ -0,0 +1,15 @@ +using Windows.UI.Xaml.Media; + +namespace UICompositionAnimations.Behaviours.Xaml.Effects +{ + /// + /// A backdrop effect that can sample from a specified source + /// + public sealed class BackdropEffect : IPipelineEffect + { + /// + /// Gets or sets the backdrop source to use to render the effect + /// + public AcrylicBackgroundSource Source { get; set; } + } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/BlendEffect.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/BlendEffect.cs new file mode 100644 index 0000000..aafaf9c --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/BlendEffect.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using Microsoft.Graphics.Canvas.Effects; +using UICompositionAnimations.Enums; + +namespace UICompositionAnimations.Behaviours.Xaml.Effects +{ + /// + /// A blend effect that merges the current pipeline with an input one + /// + public sealed class BlendEffect : IPipelineEffect + { + /// + /// Gets or sets the input pipeline to merge with the current instance + /// + [NotNull, ItemNotNull] + public IList Input { get; set; } = new List(); + + /// + /// Gets or sets the blending mode to use (the default mode is ) + /// + public BlendEffectMode Mode { get; set; } + + /// + /// Gets or sets the placement of the input pipeline with respect to the current one (the default is ) + /// + public EffectPlacement Placement { get; set; } = EffectPlacement.Foreground; + } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/BlurEffect.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/BlurEffect.cs new file mode 100644 index 0000000..5d25528 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/BlurEffect.cs @@ -0,0 +1,9 @@ +using UICompositionAnimations.Behaviours.Xaml.Effects.Abstract; + +namespace UICompositionAnimations.Behaviours.Xaml.Effects +{ + /// + /// A gaussian blur effect + /// + public sealed class BlurEffect : ValueEffectBase { } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/ImageEffect.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/ImageEffect.cs new file mode 100644 index 0000000..5f159f3 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/ImageEffect.cs @@ -0,0 +1,9 @@ +using UICompositionAnimations.Behaviours.Xaml.Effects.Abstract; + +namespace UICompositionAnimations.Behaviours.Xaml.Effects +{ + /// + /// An image effect, which displays an image loaded as a Win2D surface + /// + public sealed class ImageEffect : ImageEffectBase { } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/LuminanceEffect.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/LuminanceEffect.cs new file mode 100644 index 0000000..f98cce9 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/LuminanceEffect.cs @@ -0,0 +1,7 @@ +namespace UICompositionAnimations.Behaviours.Xaml.Effects +{ + /// + /// A luminance effect which directly replicates + /// + public sealed class LuminanceEffect : IPipelineEffect { } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/OpacityEffect.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/OpacityEffect.cs new file mode 100644 index 0000000..04f49f9 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/OpacityEffect.cs @@ -0,0 +1,9 @@ +using UICompositionAnimations.Behaviours.Xaml.Effects.Abstract; + +namespace UICompositionAnimations.Behaviours.Xaml.Effects +{ + /// + /// A simple opacity effect + /// + public sealed class OpacityEffect : ValueEffectBase { } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/SaturationEffect.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/SaturationEffect.cs new file mode 100644 index 0000000..78a7efc --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/SaturationEffect.cs @@ -0,0 +1,9 @@ +using UICompositionAnimations.Behaviours.Xaml.Effects.Abstract; + +namespace UICompositionAnimations.Behaviours.Xaml.Effects +{ + /// + /// A saturation effect + /// + public sealed class SaturationEffect : ValueEffectBase { } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/SolidColorEffect.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/SolidColorEffect.cs new file mode 100644 index 0000000..05a1003 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/SolidColorEffect.cs @@ -0,0 +1,15 @@ +using Windows.UI; + +namespace UICompositionAnimations.Behaviours.Xaml.Effects +{ + /// + /// A simple effect that renders a solid color on the available surface + /// + public sealed class SolidColorEffect : IPipelineEffect + { + /// + /// Gets or sets the color to display + /// + public Color Color { get; set; } + } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/TileEffect.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/TileEffect.cs new file mode 100644 index 0000000..ca9d942 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/TileEffect.cs @@ -0,0 +1,9 @@ +using UICompositionAnimations.Behaviours.Xaml.Effects.Abstract; + +namespace UICompositionAnimations.Behaviours.Xaml.Effects +{ + /// + /// An effect that loads an image and replicates it to cover all the available surface area + /// + public sealed class TileEffect : ImageEffectBase { } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/Effects/TintEffect.cs b/UICompositionAnimations/Behaviours/Xaml/Effects/TintEffect.cs new file mode 100644 index 0000000..404c465 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/Effects/TintEffect.cs @@ -0,0 +1,20 @@ +using Windows.UI; + +namespace UICompositionAnimations.Behaviours.Xaml.Effects +{ + /// + /// A tint effect with a customizable opacity + /// + public sealed class TintEffect : IPipelineEffect + { + /// + /// Gets or sets the tint color to use + /// + public Color Color { get; set; } + + /// + /// Gets or sets the opacity of the tint effect + /// + public double Opacity { get; set; } + } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/IPipelineEffect.cs b/UICompositionAnimations/Behaviours/Xaml/IPipelineEffect.cs new file mode 100644 index 0000000..6f8c954 --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/IPipelineEffect.cs @@ -0,0 +1,7 @@ +namespace UICompositionAnimations.Behaviours.Xaml +{ + /// + /// The base for all the pipeline effects to be used in a + /// + public interface IPipelineEffect { } +} diff --git a/UICompositionAnimations/Behaviours/Xaml/PipelineBrush.cs b/UICompositionAnimations/Behaviours/Xaml/PipelineBrush.cs new file mode 100644 index 0000000..8bed0eb --- /dev/null +++ b/UICompositionAnimations/Behaviours/Xaml/PipelineBrush.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Windows.UI.Xaml.Media; +using JetBrains.Annotations; +using UICompositionAnimations.Behaviours.Xaml.Effects; +using UICompositionAnimations.Brushes.Base; +using LuminanceToAlphaEffect = Microsoft.Graphics.Canvas.Effects.LuminanceToAlphaEffect; + +namespace UICompositionAnimations.Behaviours.Xaml +{ + /// + /// A that renders a customizable Composition/Win2D effects pipeline + /// + public sealed class PipelineBrush : XamlCompositionEffectBrushBase + { + /// + protected override CompositionBrushBuilder OnBrushRequested() + { + // Starts a new composition pipeline from the given effect + CompositionBrushBuilder Start(IPipelineEffect effect) + { + switch (effect) + { + case BackdropEffect backdrop when backdrop.Source == AcrylicBackgroundSource.Backdrop: + return CompositionBrushBuilder.FromBackdropBrush(); + case BackdropEffect backdrop when backdrop.Source == AcrylicBackgroundSource.HostBackdrop: + return CompositionBrushBuilder.FromHostBackdropBrush(); + case SolidColorEffect color: return CompositionBrushBuilder.FromColor(color.Color); + case ImageEffect image: return CompositionBrushBuilder.FromImage(image.Uri, image.DPIMode, image.CacheMode); + case TileEffect tile: return CompositionBrushBuilder.FromTiles(tile.Uri, tile.DPIMode, tile.CacheMode); + default: throw new ArgumentException($"Invalid initial pipeline effect: {effect.GetType()}"); + } + } + + // Appends an effect to an existing composition pipeline + CompositionBrushBuilder Append(IPipelineEffect effect, CompositionBrushBuilder builder) + { + switch (effect) + { + case OpacityEffect opacity: return builder.Opacity((float)opacity.Value); + case LuminanceEffect _: return builder.Effect(source => new LuminanceToAlphaEffect { Source = source }); + case TintEffect tint: return builder.Tint(tint.Color, (float)tint.Opacity); + case BlurEffect blur: return builder.Blur((float)blur.Value); + case SaturationEffect saturation: return builder.Saturation((float)saturation.Value); + case BlendEffect blend: return builder.Blend(Build(blend.Input), blend.Mode, blend.Placement); + default: throw new ArgumentException($"Invalid pipeline effect: {effect.GetType()}"); + } + } + + // Builds a new effects pipeline from the input effects sequence + CompositionBrushBuilder Build(IList effects) + { + if (effects.Count == 0) throw new ArgumentException("An effects pipeline can't be empty"); + return effects.Skip(1).Aggregate(Start(effects[0]), (b, e) => Append(e, b)); + } + + return Build(Effects); + } + + /// + /// Gets or sets the collection of effects to use in the current pipeline + /// + [NotNull, ItemNotNull] + public IList Effects { get; set; } = new List(); + } +} diff --git a/UICompositionAnimations/Brushes/CustomAcrylicBrush.cs b/UICompositionAnimations/Brushes/CustomAcrylicBrush.cs index 4589b85..df67cc5 100644 --- a/UICompositionAnimations/Brushes/CustomAcrylicBrush.cs +++ b/UICompositionAnimations/Brushes/CustomAcrylicBrush.cs @@ -8,19 +8,18 @@ using Windows.UI.Composition; using Windows.UI.Xaml; using Windows.UI.Xaml.Media; -using JetBrains.Annotations; using UICompositionAnimations.Behaviours; using UICompositionAnimations.Brushes.Cache; using UICompositionAnimations.Enums; using UICompositionAnimations.Helpers; using Windows.ApplicationModel; +using JetBrains.Annotations; namespace UICompositionAnimations.Brushes { /// /// A custom XAML brush that includes an acrylic effect that blurs the in-app content /// - [PublicAPI] public sealed class CustomAcrylicBrush : XamlCompositionBrushBase { #region Constants @@ -304,6 +303,7 @@ protected override async void OnDisconnected() /// /// Clears the internal cache of instances /// + [PublicAPI] public static async Task ClearCacheAsync(AcrylicEffectMode targets) { // In-app backdrop brush diff --git a/UICompositionAnimations/Properties/AssemblyInfo.cs b/UICompositionAnimations/Properties/AssemblyInfo.cs index e5a55dc..9e38cf0 100644 --- a/UICompositionAnimations/Properties/AssemblyInfo.cs +++ b/UICompositionAnimations/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Sergio Pedri")] [assembly: AssemblyProduct("UICompositionAnimations")] -[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyCopyright("Copyright © 2019")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -23,8 +23,8 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.1.0")] -[assembly: AssemblyFileVersion("3.0.1.0")] -[assembly: AssemblyInformationalVersion("3.0.1")] +[assembly: AssemblyVersion("3.1.0.0")] +[assembly: AssemblyFileVersion("3.1.0.0")] +[assembly: AssemblyInformationalVersion("3.1.0")] [assembly: ComVisible(false)] diff --git a/UICompositionAnimations/UICompositionAnimations.csproj b/UICompositionAnimations/UICompositionAnimations.csproj index ae2433a..7b44c92 100644 --- a/UICompositionAnimations/UICompositionAnimations.csproj +++ b/UICompositionAnimations/UICompositionAnimations.csproj @@ -123,6 +123,20 @@ + + + + + + + + + + + + + + @@ -164,7 +178,7 @@ - 2018.2.1 + 2018.3.0 6.1.9 diff --git a/UICompositionAnimations/UICompositionAnimations.nuspec b/UICompositionAnimations/UICompositionAnimations.nuspec index 5ab12da..9c3aed5 100644 --- a/UICompositionAnimations/UICompositionAnimations.nuspec +++ b/UICompositionAnimations/UICompositionAnimations.nuspec @@ -2,19 +2,19 @@ UICompositionAnimations - 3.0.1 + 3.1.0 UICompositionAnimations A wrapper UWP PCL to work with Windows.UI.Composition and XAML animations, and Win2D effects Sergio Pedri Sergio Pedri https://github.com/Sergio0694/UICompositionAnimations - https://github.com/Sergio0694/UICompositionAnimations/blob/master/LICENSE.md + GPL-3.0-only false - Added new pointer events handling APIs - Copyright © 2018 + New PipelineBrush and composition effect APIs + Copyright © 2010 uwp composition animations xaml csharp windows winrt universal app ui win2d graphics - +