Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ported source code for CommunityToolkit.WinUI.Media #113

Merged
merged 15 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions components/Animations/src/ArgumentNullExceptionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 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.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace System;

/// <summary>
/// Throw helper extensions for <see cref="ArgumentNullException"/>.
/// </summary>
internal static class ArgumentNullExceptionExtensions
{
/// <summary>
/// Throws an <see cref="ArgumentNullException"/> for a given parameter name.
/// </summary>
/// <param name="_">Dummy value to invoke the extension upon (always pass <see langword="null"/>.</param>
/// <param name="parameterName">The name of the parameter to report in the exception.</param>
/// <exception cref="ArgumentNullException">Thrown with <paramref name="parameterName"/>.</exception>
[DoesNotReturn]
public static void Throw(this ArgumentNullException? _, string? parameterName)
{
throw new ArgumentNullException(parameterName);
}

/// <summary>
/// Throws an <see cref="ArgumentNullException"/> if <paramref name="argument"/> is <see langword="null"/>.
/// </summary>
/// <param name="_">Dummy value to invoke the extension upon (always pass <see langword="null"/>.</param>
/// <param name="argument">The reference type argument to validate as non-<see langword="null"/>.</param>
/// <param name="parameterName">The name of the parameter with which <paramref name="argument"/> corresponds.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="argument"/> is <see langword="null"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ThrowIfNull(this ArgumentNullException? _, [NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? parameterName = null)
{
if (argument is null)
{
Throw(parameterName);
}
}

/// <summary>
/// Throws an <see cref="ArgumentNullException"/> if <paramref name="argument"/> is <see langword="null"/>.
/// </summary>
/// <param name="_">Dummy value to invoke the extension upon (always pass <see langword="null"/>.</param>
/// <param name="argument">The pointer argument to validate as non-<see langword="null"/>.</param>
/// <param name="parameterName">The name of the parameter with which <paramref name="argument"/> corresponds.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="argument"/> is <see langword="null"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void ThrowIfNull(this ArgumentNullException? _, [NotNull] void* argument, [CallerArgumentExpression(nameof(argument))] string? parameterName = null)
{
if (argument is null)
{
Throw(parameterName);
}
}

/// <inheritdoc cref="Throw(ArgumentNullException?, string?)"/>
[DoesNotReturn]
private static void Throw(string? parameterName)
{
throw new ArgumentNullException(parameterName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#if WINAPPSDK
#if WINUI3
using Microsoft.UI.Composition;
#else
#elif WINUI2
using Windows.UI.Composition;
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

<ItemGroup>
<InternalsVisibleTo Include="CommunityToolkit.WinUI.Behaviors.Animations" />
<InternalsVisibleTo Include="CommunityToolkit.WinUI.Media" />

<PackageReference Include="PolySharp" Version="1.13.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,13 @@ public IList<IKeyFrame<TKeyFrame>> KeyFrames
/// <summary>
/// Gets the explicit target for the animation. This is the primary target property that is animated.
/// </summary>
protected abstract string ExplicitTarget { get; }
protected abstract string? ExplicitTarget { get; }

/// <inheritdoc/>
public override AnimationBuilder AppendToBuilder(AnimationBuilder builder, TimeSpan? delayHint, TimeSpan? durationHint, EasingType? easingTypeHint, EasingMode? easingModeHint)
{
default(ArgumentNullException).ThrowIfNull(ExplicitTarget);
michael-hawker marked this conversation as resolved.
Show resolved Hide resolved

return builder.NormalizedKeyFrames<TKeyFrame, (Animation<TValue, TKeyFrame> This, EasingType? EasingTypeHint, EasingMode? EasingModeHint)>(
property: ExplicitTarget,
state: (this, easingTypeHint, easingModeHint),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ public abstract class CustomAnimation<TValue, TKeyFrame> : ImplicitAnimation<TVa
public FrameworkLayer Layer { get; set; }

/// <inheritdoc/>
protected override string ExplicitTarget => Target!;
protected override string? ExplicitTarget => Target;

/// <inheritdoc/>
public override AnimationBuilder AppendToBuilder(AnimationBuilder builder, TimeSpan? delayHint, TimeSpan? durationHint, EasingType? easingTypeHint, EasingMode? easingModeHint)
{
default(ArgumentNullException).ThrowIfNull(ExplicitTarget);

return builder.NormalizedKeyFrames<TKeyFrame, (CustomAnimation<TValue, TKeyFrame> This, EasingType? EasingTypeHint, EasingMode? EasingModeHint)>(
property: ExplicitTarget,
state: (this, easingTypeHint, easingModeHint),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ protected ImplicitAnimation()
/// <inheritdoc/>
public CompositionAnimation GetAnimation(UIElement element, out string? target)
{
default(ArgumentNullException).ThrowIfNull(ExplicitTarget);

NormalizedKeyFrameAnimationBuilder<TKeyFrame>.Composition builder = new(
ExplicitTarget,
Delay ?? DefaultDelay,
Expand Down
4 changes: 1 addition & 3 deletions components/Animations/src/Xaml/Default/ClipAnimation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ namespace CommunityToolkit.WinUI.Animations;
public sealed class ClipAnimation : Animation<Thickness?, Thickness>
{
/// <inheritdoc/>
#pragma warning disable CA1065 // Do not raise exceptions in unexpected locations
protected override string ExplicitTarget => throw new NotImplementedException();
#pragma warning restore CA1065 // Do not raise exceptions in unexpected locations
protected override string? ExplicitTarget => null;

/// <inheritdoc/>
public override AnimationBuilder AppendToBuilder(AnimationBuilder builder, TimeSpan? delayHint, TimeSpan? durationHint, EasingType? easingTypeHint, EasingMode? easingModeHint)
Expand Down
5 changes: 4 additions & 1 deletion components/Extensions/src/Markup/FontIconExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ public class FontIconExtension : TextIconExtension
public FontFamily? FontFamily { get; set; }

/// <inheritdoc/>
protected override object ProvideValue()
protected override object? ProvideValue()
Arlodotexe marked this conversation as resolved.
Show resolved Hide resolved
{
if (Glyph is null || string.IsNullOrWhiteSpace(Glyph))
return null;

var fontIcon = new FontIcon
{
Glyph = Glyph,
Expand Down
3 changes: 3 additions & 0 deletions components/Media/OpenSolution.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@ECHO OFF

powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %*
Binary file added components/Media/samples/Assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions components/Media/samples/Dependencies.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.

MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.

For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
</ItemGroup>

<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
</ItemGroup>
</Project>
8 changes: 8 additions & 0 deletions components/Media/samples/Media.Samples.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
<PropertyGroup>
<ToolkitComponentName>Media</ToolkitComponentName>
</PropertyGroup>

<!-- Sets this up as a toolkit component's sample project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" />
</Project>
13 changes: 13 additions & 0 deletions components/Media/src/AdditionalAssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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.Runtime.CompilerServices;

// These `InternalsVisibleTo` calls are intended to make it easier for
// for any internal code to be testable in all the different test projects
// used with the Labs infrastructure.
[assembly: InternalsVisibleTo("Media.Tests.Uwp")]
[assembly: InternalsVisibleTo("Media.Tests.WinAppSdk")]
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.Uwp")]
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.WinAppSdk")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// 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 CommunityToolkit.WinUI.Media;
using static CommunityToolkit.WinUI.Animations.AnimationExtensions;

#if WINUI2
using Windows.UI.Composition;
#elif WINUI3
using Microsoft.UI.Composition;
#endif

namespace CommunityToolkit.WinUI.Animations;

/// <summary>
/// A custom animation targeting a property on an <see cref="IPipelineEffect"/> instance.
/// </summary>
/// <typeparam name="TEffect">The type of effect to animate.</typeparam>
/// <typeparam name="TValue">
/// The type to use for the public <see cref="Animation{TValue,TKeyFrame}.To"/> and <see cref="Animation{TValue,TKeyFrame}.From"/>
/// properties. This can differ from <typeparamref name="TKeyFrame"/> to facilitate XAML parsing.
/// </typeparam>
/// <typeparam name="TKeyFrame">The actual type of keyframe values in use.</typeparam>
public abstract class EffectAnimation<TEffect, TValue, TKeyFrame> : Animation<TValue, TKeyFrame>
where TEffect : class, IPipelineEffect
where TKeyFrame : unmanaged
{
/// <summary>
/// Gets or sets the linked <typeparamref name="TEffect"/> instance to animate.
/// </summary>
public TEffect? Target
{
get => (TEffect?)GetValue(TargetProperty);
set => SetValue(TargetProperty, value);
}

/// <summary>
/// Identifies the <seealso cref="Target"/> dependency property.
/// </summary>
public static readonly DependencyProperty TargetProperty = DependencyProperty.Register(
nameof(Target),
typeof(TEffect),
typeof(EffectAnimation<TEffect, TValue, TKeyFrame>),
new PropertyMetadata(null));

/// <inheritdoc/>
public override AnimationBuilder AppendToBuilder(AnimationBuilder builder, TimeSpan? delayHint, TimeSpan? durationHint, EasingType? easingTypeHint, EasingMode? easingModeHint)
{
if (Target is not TEffect target)
{
static AnimationBuilder ThrowArgumentNullException() => throw new ArgumentNullException("The target effect is null, make sure to set the Target property");

return ThrowArgumentNullException();
}

if (ExplicitTarget is not string explicitTarget)
{
static AnimationBuilder ThrowArgumentNullException()
{
throw new ArgumentNullException(
"The target effect cannot be animated at this time. If you're targeting one of the " +
"built-in effects, make sure that the PipelineEffect.IsAnimatable property is set to true.");
}

return ThrowArgumentNullException();
}

NormalizedKeyFrameAnimationBuilder<TKeyFrame>.Composition keyFrameBuilder = new(
explicitTarget,
Delay ?? delayHint ?? DefaultDelay,
Duration ?? durationHint ?? DefaultDuration,
Repeat,
DelayBehavior);

AppendToBuilder(keyFrameBuilder, easingTypeHint, easingModeHint);

CompositionAnimation animation = keyFrameBuilder.GetAnimation(target.Brush!, out _);

return builder.ExternalAnimation(target.Brush!, animation);
}
}
22 changes: 22 additions & 0 deletions components/Media/src/Animations/BlurEffectAnimation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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 CommunityToolkit.WinUI.Media;

namespace CommunityToolkit.WinUI.Animations;

/// <summary>
/// An effect animation that targets <see cref="BlurEffect.Amount"/>.
/// </summary>
public sealed class BlurEffectAnimation : EffectAnimation<BlurEffect, double?, double>
{
/// <inheritdoc/>
protected override string? ExplicitTarget => Target?.Id;

/// <inheritdoc/>
protected override (double?, double?) GetParsedValues()
{
return (To, From);
}
}
23 changes: 23 additions & 0 deletions components/Media/src/Animations/ColorEffectAnimation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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 CommunityToolkit.WinUI.Media;
using Windows.UI;

namespace CommunityToolkit.WinUI.Animations;

/// <summary>
/// An effect animation that targets <see cref="TintEffect.Color"/>.
/// </summary>
public sealed class ColorEffectAnimation : EffectAnimation<TintEffect, Color?, Color>
{
/// <inheritdoc/>
protected override string? ExplicitTarget => Target?.Id;

/// <inheritdoc/>
protected override (Color?, Color?) GetParsedValues()
{
return (To, From);
}
}
22 changes: 22 additions & 0 deletions components/Media/src/Animations/CrossFadeEffectAnimation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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 CommunityToolkit.WinUI.Media;

namespace CommunityToolkit.WinUI.Animations;

/// <summary>
/// An effect animation that targets <see cref="CrossFadeEffect.Factor"/>.
/// </summary>
public sealed class CrossFadeEffectAnimation : EffectAnimation<CrossFadeEffect, double?, double>
{
/// <inheritdoc/>
protected override string? ExplicitTarget => Target?.Id;

/// <inheritdoc/>
protected override (double?, double?) GetParsedValues()
{
return (To, From);
}
}
22 changes: 22 additions & 0 deletions components/Media/src/Animations/ExposureEffectAnimation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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 CommunityToolkit.WinUI.Media;

namespace CommunityToolkit.WinUI.Animations;

/// <summary>
/// An effect animation that targets <see cref="ExposureEffect.Amount"/>.
/// </summary>
public sealed class ExposureEffectAnimation : EffectAnimation<ExposureEffect, double?, double>
{
/// <inheritdoc/>
protected override string? ExplicitTarget => Target?.Id;

/// <inheritdoc/>
protected override (double?, double?) GetParsedValues()
{
return (To, From);
}
}
Loading