-
Notifications
You must be signed in to change notification settings - Fork 141
Expand file tree
/
Copy pathNormalizedKeyFrameAnimationBuilder{T}.cs
More file actions
193 lines (165 loc) · 6.27 KB
/
NormalizedKeyFrameAnimationBuilder{T}.cs
File metadata and controls
193 lines (165 loc) · 6.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// 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.
#if WINAPPSDK
using Microsoft.UI.Composition;
#else
using Windows.UI.Composition;
#endif
using System.Runtime.CompilerServices;
using CommunityToolkit.WinUI.Animations.Builders.Helpers;
namespace CommunityToolkit.WinUI.Animations;
/// <summary>
/// A generic keyframe animation builder.
/// </summary>
/// <typeparam name="T">The type of values being set by the animation being constructed.</typeparam>
public abstract partial class NormalizedKeyFrameAnimationBuilder<T> : INormalizedKeyFrameAnimationBuilder<T>
where T : unmanaged
{
/// <summary>
/// The target property to animate.
/// </summary>
private readonly string property;
/// <summary>
/// The target delay for the animation, if any.
/// </summary>
private readonly TimeSpan? delay;
/// <summary>
/// The target duration for the animation.
/// </summary>
private readonly TimeSpan duration;
/// <summary>
/// The repeat options for the animation.
/// </summary>
private readonly RepeatOption repeat;
/// <summary>
/// The list builder of keyframes to use.
/// </summary>
private ListBuilder<KeyFrameInfo> keyFrames = ListBuilder<KeyFrameInfo>.Empty;
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedKeyFrameAnimationBuilder{T}"/> class.
/// </summary>
/// <param name="property">The target property to animate.</param>
/// <param name="delay">The target delay for the animation.</param>
/// <param name="duration">The target duration for the animation.</param>
/// <param name="repeat">The repeat options for the animation.</param>
protected NormalizedKeyFrameAnimationBuilder(string property, TimeSpan? delay, TimeSpan duration, RepeatOption repeat)
{
this.property = property;
this.delay = delay;
this.duration = duration;
this.repeat = repeat;
}
/// <inheritdoc/>
public INormalizedKeyFrameAnimationBuilder<T> KeyFrame(
double progress,
T value,
EasingType easingType,
EasingMode easingMode)
{
this.keyFrames.Append(new(progress, value, easingType, easingMode));
return this;
}
/// <inheritdoc/>
public abstract INormalizedKeyFrameAnimationBuilder<T> ExpressionKeyFrame(
double progress,
string expression,
EasingType easingType,
EasingMode easingMode);
/// <summary>
/// The abstracted info for a normalized animation keyframe.
/// </summary>
protected readonly struct KeyFrameInfo : IKeyFrameInfo
{
/// <summary>
/// The normalized progress for the keyframe.
/// </summary>
private readonly double progress;
/// <summary>
/// The value for the current keyframe.
/// </summary>
private readonly T value;
/// <summary>
/// The expression for the current keyframe, if present.
/// </summary>
private readonly string? expression;
/// <summary>
/// Initializes a new instance of the <see cref="KeyFrameInfo"/> struct.
/// </summary>
/// <param name="progress">The normalized progress for the keyframe.</param>
/// <param name="value">The value for the new keyframe to add.</param>
/// <param name="easingType">The easing type to use to reach the new keyframe.</param>
/// <param name="easingMode">The easing mode to use to reach the new keyframe.</param>
public KeyFrameInfo(
double progress,
T value,
EasingType easingType,
EasingMode easingMode)
{
this.progress = progress;
this.value = value;
this.expression = null;
EasingType = easingType;
EasingMode = easingMode;
}
/// <summary>
/// Initializes a new instance of the <see cref="KeyFrameInfo"/> struct.
/// </summary>
/// <param name="progress">The normalized progress for the keyframe.</param>
/// <param name="expression">The expression for the new keyframe to add.</param>
/// <param name="easingType">The easing type to use to reach the new keyframe.</param>
/// <param name="easingMode">The easing mode to use to reach the new keyframe.</param>
public KeyFrameInfo(
double progress,
string expression,
EasingType easingType,
EasingMode easingMode)
{
this.progress = progress;
this.value = default;
this.expression = expression;
EasingType = easingType;
EasingMode = easingMode;
}
/// <inheritdoc/>
public EasingType EasingType { get; }
/// <inheritdoc/>
public EasingMode EasingMode { get; }
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TValue GetValueAs<TValue>()
{
return (TValue)(object)this.value;
}
/// <inheritdoc/>
public bool TryInsertExpressionKeyFrame(KeyFrameAnimation animation, TimeSpan duration)
{
if (this.expression is null)
{
return false;
}
CompositionEasingFunction? easingFunction = animation.Compositor.TryCreateEasingFunction(EasingType, EasingMode);
if (easingFunction is null)
{
animation.InsertExpressionKeyFrame((float)this.progress, this.expression);
}
else
{
animation.InsertExpressionKeyFrame((float)this.progress, this.expression, easingFunction);
}
return true;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetNormalizedProgress(TimeSpan duration)
{
return (float)this.progress;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TimeSpan GetTimedProgress(TimeSpan duration)
{
return TimeSpan.FromMilliseconds(duration.TotalMilliseconds * this.progress);
}
}
}