A game framework written with osu! in mind.
at master 783 lines 51 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using osuTK; 5using osuTK.Graphics; 6using osu.Framework.Graphics.Colour; 7using osu.Framework.Graphics.Containers; 8using osu.Framework.Graphics.Transforms; 9using System; 10using System.Linq; 11using JetBrains.Annotations; 12using osu.Framework.Bindables; 13using osu.Framework.Graphics.Effects; 14using osu.Framework.Utils; 15 16namespace osu.Framework.Graphics 17{ 18 public static class TransformableExtensions 19 { 20 /// <summary> 21 /// Transforms a given property or field member of a given <see cref="ITransformable"/> <typeparamref name="TThis"/> to <paramref name="newValue"/>. 22 /// The value of the given member is smoothly changed over time using the given <paramref name="easing"/> for tweening. 23 /// </summary> 24 /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> to apply the <see cref="Transform{TValue, T}"/> to.</typeparam> 25 /// <typeparam name="TValue">The value type which is being transformed.</typeparam> 26 /// <param name="t">The <see cref="ITransformable"/> to apply the <see cref="Transform{TValue, T}"/> to.</param> 27 /// <param name="propertyOrFieldName">The property or field name of the member ot <typeparamref name="TThis"/> to transform.</param> 28 /// <param name="newValue">The value to transform to.</param> 29 /// <param name="duration">The transform duration.</param> 30 /// <param name="easing">The transform easing to be used for tweening.</param> 31 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 32 public static TransformSequence<TThis> TransformTo<TThis, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration = 0, Easing easing = Easing.None) 33 where TThis : class, ITransformable 34 => t.TransformTo(t.MakeTransform(propertyOrFieldName, newValue, duration, new DefaultEasingFunction(easing))); 35 36 /// <summary> 37 /// Transforms a given property or field member of a given <see cref="ITransformable"/> <typeparamref name="TThis"/> to <paramref name="newValue"/>. 38 /// The value of the given member is smoothly changed over time using the given <paramref name="easing"/> for tweening. 39 /// </summary> 40 /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> to apply the <see cref="Transform{TValue, T}"/> to.</typeparam> 41 /// <typeparam name="TValue">The value type which is being transformed.</typeparam> 42 /// <typeparam name="TEasing">The type of easing.</typeparam> 43 /// <param name="t">The <see cref="ITransformable"/> to apply the <see cref="Transform{TValue, T}"/> to.</param> 44 /// <param name="propertyOrFieldName">The property or field name of the member ot <typeparamref name="TThis"/> to transform.</param> 45 /// <param name="newValue">The value to transform to.</param> 46 /// <param name="duration">The transform duration.</param> 47 /// <param name="easing">The transform easing to be used for tweening.</param> 48 /// <param name="grouping">An optional grouping specification to be used when the same property may be touched by multiple transform types.</param> 49 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 50 public static TransformSequence<TThis> TransformTo<TThis, TValue, TEasing>(this TThis t, string propertyOrFieldName, TValue newValue, double duration, in TEasing easing, string grouping = null) 51 where TThis : class, ITransformable 52 where TEasing : IEasingFunction 53 => t.TransformTo(t.MakeTransform(propertyOrFieldName, newValue, duration, easing, grouping)); 54 55 /// <summary> 56 /// Applies a <see cref="Transform"/> to a given <see cref="ITransformable"/>. 57 /// </summary> 58 /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> to apply the <see cref="Transform"/> to.</typeparam> 59 /// <param name="t">The <see cref="ITransformable"/> to apply the <see cref="Transform{TValue, T}"/> to.</param> 60 /// <param name="transform">The transform to use.</param> 61 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 62 public static TransformSequence<TThis> TransformTo<TThis>(this TThis t, Transform transform) where TThis : class, ITransformable 63 { 64 var result = new TransformSequence<TThis>(t); 65 result.Add(transform); 66 t.AddTransform(transform); 67 return result; 68 } 69 70 /// <summary> 71 /// Creates a <see cref="Transform{TValue, T}"/> for smoothly changing <paramref name="propertyOrFieldName"/> 72 /// over time using the given <paramref name="easing"/> for tweening. 73 /// <see cref="PopulateTransform{TValue, DefaultEasingFunction, TThis}"/> is invoked as part of this method. 74 /// </summary> 75 /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 76 /// <typeparam name="TValue">The value type which is being transformed.</typeparam> 77 /// <param name="t">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 78 /// <param name="propertyOrFieldName">The property or field name of the member ot <typeparamref name="TThis"/> to transform.</param> 79 /// <param name="newValue">The value to transform to.</param> 80 /// <param name="duration">The transform duration.</param> 81 /// <param name="easing">The transform easing to be used for tweening.</param> 82 /// <param name="grouping">An optional grouping specification to be used when the same property may be touched by multiple transform types.</param> 83 /// <returns>The resulting <see cref="Transform{TValue, T}"/>.</returns> 84 public static Transform<TValue, DefaultEasingFunction, TThis> MakeTransform<TThis, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration = 0, 85 Easing easing = Easing.None, string grouping = null) 86 where TThis : class, ITransformable 87 => t.MakeTransform(propertyOrFieldName, newValue, duration, new DefaultEasingFunction(easing), grouping); 88 89 /// <summary> 90 /// Creates a <see cref="Transform{TValue, T}"/> for smoothly changing <paramref name="propertyOrFieldName"/> 91 /// over time using the given <paramref name="easing"/> for tweening. 92 /// <see cref="PopulateTransform{TValue, TEasing, TThis}"/> is invoked as part of this method. 93 /// </summary> 94 /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 95 /// <typeparam name="TValue">The value type which is being transformed.</typeparam> 96 /// <typeparam name="TEasing">The type of easing.</typeparam> 97 /// <param name="t">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 98 /// <param name="propertyOrFieldName">The property or field name of the member ot <typeparamref name="TThis"/> to transform.</param> 99 /// <param name="newValue">The value to transform to.</param> 100 /// <param name="duration">The transform duration.</param> 101 /// <param name="easing">The transform easing to be used for tweening.</param> 102 /// <param name="grouping">An optional grouping specification to be used when the same property may be touched by multiple transform types.</param> 103 /// <returns>The resulting <see cref="Transform{TValue, T}"/>.</returns> 104 public static Transform<TValue, TEasing, TThis> MakeTransform<TThis, TEasing, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration, in TEasing easing, string grouping = null) 105 where TThis : class, ITransformable 106 where TEasing : IEasingFunction 107 => t.PopulateTransform(new TransformCustom<TValue, TEasing, TThis>(propertyOrFieldName, grouping), newValue, duration, easing); 108 109 /// <summary> 110 /// Populates a newly created <see cref="Transform{TValue, T}"/> with necessary values. 111 /// All <see cref="Transform{TValue, T}"/>s must be populated by this method prior to being used. 112 /// </summary> 113 /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 114 /// <typeparam name="TValue">The value type which is being transformed.</typeparam> 115 /// <param name="t">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 116 /// <param name="transform">The transform to populate.</param> 117 /// <param name="newValue">The value to transform to.</param> 118 /// <param name="duration">The transform duration.</param> 119 /// <param name="easing">The transform easing to be used for tweening.</param> 120 /// <returns>The populated <paramref name="transform"/>.</returns> 121 public static Transform<TValue, DefaultEasingFunction, TThis> PopulateTransform<TValue, TThis>(this TThis t, Transform<TValue, DefaultEasingFunction, TThis> transform, TValue newValue, 122 double duration = 0, Easing easing = Easing.None) 123 where TThis : class, ITransformable 124 => t.PopulateTransform(transform, newValue, duration, new DefaultEasingFunction(easing)); 125 126 /// <summary> 127 /// Populates a newly created <see cref="Transform{TValue, T}"/> with necessary values. 128 /// All <see cref="Transform{TValue, T}"/>s must be populated by this method prior to being used. 129 /// </summary> 130 /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 131 /// <typeparam name="TValue">The value type which is being transformed.</typeparam> 132 /// <typeparam name="TEasing">The type of easing.</typeparam> 133 /// <param name="t">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 134 /// <param name="transform">The transform to populate.</param> 135 /// <param name="newValue">The value to transform to.</param> 136 /// <param name="duration">The transform duration.</param> 137 /// <param name="easing">The transform easing to be used for tweening.</param> 138 /// <returns>The populated <paramref name="transform"/>.</returns> 139 public static Transform<TValue, TEasing, TThis> PopulateTransform<TValue, TEasing, TThis>(this TThis t, Transform<TValue, TEasing, TThis> transform, TValue newValue, double duration, 140 in TEasing easing) 141 where TThis : class, ITransformable 142 where TEasing : IEasingFunction 143 { 144 if (duration < 0) 145 throw new ArgumentOutOfRangeException(nameof(duration), $"{nameof(duration)} must be positive."); 146 147 if (transform.Target != null) 148 throw new InvalidOperationException($"May not {nameof(PopulateTransform)} the same {nameof(Transform<TValue, TThis>)} more than once."); 149 150 transform.Target = t; 151 152 double startTime = t.TransformStartTime; 153 154 transform.StartTime = startTime; 155 transform.EndTime = startTime + duration; 156 transform.EndValue = newValue; 157 transform.Easing = easing; 158 159 return transform; 160 } 161 162 /// <summary> 163 /// Applies <paramref name="childGenerators"/> via TransformSequence.Append(IEnumerable{Generator})/>. 164 /// </summary> 165 /// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 166 /// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 167 /// <param name="childGenerators">The optional Generators for <see cref="TransformSequence{T}"/>s to be appended.</param> 168 /// <returns>This <see cref="TransformSequence{T}"/>.</returns> 169 public static TransformSequence<T> Animate<T>(this T transformable, params TransformSequence<T>.Generator[] childGenerators) where T : class, ITransformable => 170 transformable.Delay(0, childGenerators); 171 172 /// <summary> 173 /// Advances the start time of future appended <see cref="TransformSequence{T}"/>s by <paramref name="delay"/> milliseconds. 174 /// Then, <paramref name="childGenerators"/> are appended via TransformSequence.Append(IEnumerable{Generator})/>. 175 /// </summary> 176 /// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 177 /// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 178 /// <param name="delay">The delay to advance the start time by.</param> 179 /// <param name="childGenerators">The optional Generators for <see cref="TransformSequence{T}"/>s to be appended.</param> 180 /// <returns>This <see cref="TransformSequence{T}"/>.</returns> 181 public static TransformSequence<T> Delay<T>(this T transformable, double delay, params TransformSequence<T>.Generator[] childGenerators) where T : class, ITransformable => 182 new TransformSequence<T>(transformable).Delay(delay, childGenerators); 183 184 /// <summary> 185 /// Returns a <see cref="TransformSequence{T}"/> which waits for all existing transforms to finish. 186 /// </summary> 187 /// <returns>A <see cref="TransformSequence{T}"/> which has a delay waiting for all transforms to be completed.</returns> 188 public static TransformSequence<T> DelayUntilTransformsFinished<T>(this T transformable) 189 where T : Transformable => 190 transformable.Delay(Math.Max(0, transformable.LatestTransformEndTime - transformable.Time.Current)); 191 192 /// <summary> 193 /// Append a looping <see cref="TransformSequence{T}"/> to this <see cref="TransformSequence{T}"/>. 194 /// All <see cref="Transform"/>s generated by <paramref name="childGenerators"/> are appended to 195 /// this <see cref="TransformSequence{T}"/> and then repeated <paramref name="numIters"/> times 196 /// with <paramref name="pause"/> milliseconds between iterations. 197 /// </summary> 198 /// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 199 /// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 200 /// <param name="pause">The pause between iterations in milliseconds.</param> 201 /// <param name="numIters">The number of iterations.</param> 202 /// <param name="childGenerators">The functions to generate the <see cref="TransformSequence{T}"/>s to be looped.</param> 203 /// <returns>This <see cref="TransformSequence{T}"/>.</returns> 204 public static TransformSequence<T> Loop<T>(this T transformable, double pause, int numIters, params TransformSequence<T>.Generator[] childGenerators) 205 where T : class, ITransformable => 206 transformable.Delay(0).Loop(pause, numIters, childGenerators); 207 208 /// <summary> 209 /// Append a looping <see cref="TransformSequence{T}"/> to this <see cref="TransformSequence{T}"/>. 210 /// All <see cref="Transform"/>s generated by <paramref name="childGenerators"/> are appended to 211 /// this <see cref="TransformSequence{T}"/> and then repeated indefinitely with <paramref name="pause"/> 212 /// milliseconds between iterations. 213 /// </summary> 214 /// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 215 /// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 216 /// <param name="pause">The pause between iterations in milliseconds.</param> 217 /// <param name="childGenerators">The functions to generate the <see cref="TransformSequence{T}"/>s to be looped.</param> 218 /// <returns>This <see cref="TransformSequence{T}"/>.</returns> 219 public static TransformSequence<T> Loop<T>(this T transformable, double pause, params TransformSequence<T>.Generator[] childGenerators) 220 where T : class, ITransformable => 221 transformable.Delay(0).Loop(pause, childGenerators); 222 223 /// <summary> 224 /// Append a looping <see cref="TransformSequence{T}"/> to this <see cref="TransformSequence{T}"/>. 225 /// All <see cref="Transform"/>s generated by <paramref name="childGenerators"/> are appended to 226 /// this <see cref="TransformSequence{T}"/> and then repeated indefinitely. 227 /// milliseconds between iterations. 228 /// </summary> 229 /// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 230 /// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 231 /// <param name="childGenerators">The functions to generate the <see cref="TransformSequence{T}"/>s to be looped.</param> 232 /// <returns>This <see cref="TransformSequence{T}"/>.</returns> 233 public static TransformSequence<T> Loop<T>(this T transformable, params TransformSequence<T>.Generator[] childGenerators) 234 where T : class, ITransformable => 235 transformable.Delay(0).Loop(childGenerators); 236 237 /// <summary> 238 /// Append a looping <see cref="TransformSequence{T}"/> to this <see cref="TransformSequence{T}"/> to repeat indefinitely with <paramref name="pause"/> 239 /// milliseconds between iterations. 240 /// </summary> 241 /// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 242 /// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 243 /// <param name="pause">The pause between iterations in milliseconds.</param> 244 /// <returns>This <see cref="TransformSequence{T}"/>.</returns> 245 public static TransformSequence<T> Loop<T>(this T transformable, double pause = 0) 246 where T : class, ITransformable => 247 transformable.Delay(0).Loop(pause); 248 249 /// <summary> 250 /// Rotate over one full rotation with provided parameters. 251 /// </summary> 252 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 253 public static TransformSequence<T> Spin<T>(this T drawable, double revolutionDuration, RotationDirection direction, float startRotation = 0) 254 where T : Drawable 255 => drawable.Delay(0).Spin(revolutionDuration, direction, startRotation); 256 257 /// <summary> 258 /// Rotate <paramref name="numRevolutions"/> times with provided parameters. 259 /// </summary> 260 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 261 public static TransformSequence<T> Spin<T>(this T drawable, double revolutionDuration, RotationDirection direction, float startRotation, int numRevolutions) 262 where T : Drawable 263 => drawable.Delay(0).Spin(revolutionDuration, direction, startRotation, numRevolutions); 264 265 #region Easing 266 267 /// <summary> 268 /// Smoothly adjusts <see cref="Drawable.Alpha"/> to 1 over time. 269 /// </summary> 270 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 271 public static TransformSequence<T> FadeIn<T>(this T drawable, double duration = 0, Easing easing = Easing.None) 272 where T : Drawable 273 => drawable.FadeIn(duration, new DefaultEasingFunction(easing)); 274 275 /// <summary> 276 /// Smoothly adjusts <see cref="Drawable.Alpha"/> from 0 to 1 over time. 277 /// </summary> 278 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 279 public static TransformSequence<T> FadeInFromZero<T>(this T drawable, double duration = 0, Easing easing = Easing.None) 280 where T : Drawable 281 => drawable.FadeInFromZero(duration, new DefaultEasingFunction(easing)); 282 283 /// <summary> 284 /// Smoothly adjusts <see cref="Drawable.Alpha"/> to 0 over time. 285 /// </summary> 286 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 287 public static TransformSequence<T> FadeOut<T>(this T drawable, double duration = 0, Easing easing = Easing.None) 288 where T : Drawable 289 => drawable.FadeOut(duration, new DefaultEasingFunction(easing)); 290 291 /// <summary> 292 /// Smoothly adjusts <see cref="Drawable.Alpha"/> from 1 to 0 over time. 293 /// </summary> 294 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 295 public static TransformSequence<T> FadeOutFromOne<T>(this T drawable, double duration = 0, Easing easing = Easing.None) 296 where T : Drawable 297 => drawable.FadeOutFromOne(duration, new DefaultEasingFunction(easing)); 298 299 /// <summary> 300 /// Smoothly adjusts <see cref="Drawable.Alpha"/> over time. 301 /// </summary> 302 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 303 public static TransformSequence<T> FadeTo<T>(this T drawable, float newAlpha, double duration = 0, Easing easing = Easing.None) 304 where T : Drawable 305 => drawable.FadeTo(newAlpha, duration, new DefaultEasingFunction(easing)); 306 307 /// <summary> 308 /// Smoothly adjusts <see cref="Drawable.Colour"/> over time. 309 /// </summary> 310 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 311 public static TransformSequence<T> FadeColour<T>(this T drawable, ColourInfo newColour, double duration = 0, Easing easing = Easing.None) 312 where T : Drawable 313 => drawable.FadeColour(newColour, duration, new DefaultEasingFunction(easing)); 314 315 /// <summary> 316 /// Instantaneously flashes <see cref="Drawable.Colour"/>, then smoothly changes it back over time. 317 /// </summary> 318 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 319 public static TransformSequence<T> FlashColour<T>(this T drawable, ColourInfo flashColour, double duration, Easing easing = Easing.None) 320 where T : Drawable 321 => drawable.FlashColour(flashColour, duration, new DefaultEasingFunction(easing)); 322 323 /// <summary> 324 /// Smoothly adjusts <see cref="Drawable.Rotation"/> over time. 325 /// </summary> 326 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 327 public static TransformSequence<T> RotateTo<T>(this T drawable, float newRotation, double duration = 0, Easing easing = Easing.None) 328 where T : Drawable 329 => drawable.RotateTo(newRotation, duration, new DefaultEasingFunction(easing)); 330 331 /// <summary> 332 /// Smoothly adjusts <see cref="Drawable.Scale"/> over time. 333 /// </summary> 334 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 335 public static TransformSequence<T> ScaleTo<T>(this T drawable, float newScale, double duration = 0, Easing easing = Easing.None) 336 where T : Drawable 337 => drawable.ScaleTo(newScale, duration, new DefaultEasingFunction(easing)); 338 339 /// <summary> 340 /// Smoothly adjusts <see cref="Drawable.Scale"/> over time. 341 /// </summary> 342 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 343 public static TransformSequence<T> ScaleTo<T>(this T drawable, Vector2 newScale, double duration = 0, Easing easing = Easing.None) 344 where T : Drawable 345 => drawable.ScaleTo(newScale, duration, new DefaultEasingFunction(easing)); 346 347 /// <summary> 348 /// Smoothly adjusts <see cref="Drawable.Size"/> over time. 349 /// </summary> 350 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 351 public static TransformSequence<T> ResizeTo<T>(this T drawable, float newSize, double duration = 0, Easing easing = Easing.None) 352 where T : Drawable 353 => drawable.ResizeTo(newSize, duration, new DefaultEasingFunction(easing)); 354 355 /// <summary> 356 /// Smoothly adjusts <see cref="Drawable.Size"/> over time. 357 /// </summary> 358 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 359 public static TransformSequence<T> ResizeTo<T>(this T drawable, Vector2 newSize, double duration = 0, Easing easing = Easing.None) 360 where T : Drawable 361 => drawable.ResizeTo(newSize, duration, new DefaultEasingFunction(easing)); 362 363 /// <summary> 364 /// Smoothly adjusts <see cref="Drawable.Width"/> over time. 365 /// </summary> 366 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 367 public static TransformSequence<T> ResizeWidthTo<T>(this T drawable, float newWidth, double duration = 0, Easing easing = Easing.None) 368 where T : Drawable 369 => drawable.ResizeWidthTo(newWidth, duration, new DefaultEasingFunction(easing)); 370 371 /// <summary> 372 /// Smoothly adjusts <see cref="Drawable.Height"/> over time. 373 /// </summary> 374 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 375 public static TransformSequence<T> ResizeHeightTo<T>(this T drawable, float newHeight, double duration = 0, Easing easing = Easing.None) 376 where T : Drawable 377 => drawable.ResizeHeightTo(newHeight, duration, new DefaultEasingFunction(easing)); 378 379 /// <summary> 380 /// Smoothly adjusts <see cref="Drawable.Position"/> over time. 381 /// </summary> 382 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 383 public static TransformSequence<T> MoveTo<T>(this T drawable, Vector2 newPosition, double duration = 0, Easing easing = Easing.None) 384 where T : Drawable 385 => drawable.MoveTo(newPosition, duration, new DefaultEasingFunction(easing)); 386 387 /// <summary> 388 /// Smoothly adjusts <see cref="Drawable.X"/> or <see cref="Drawable.Y"/> over time. 389 /// </summary> 390 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 391 public static TransformSequence<T> MoveTo<T>(this T drawable, Direction direction, float destination, double duration = 0, Easing easing = Easing.None) 392 where T : Drawable 393 => drawable.MoveTo(direction, destination, duration, new DefaultEasingFunction(easing)); 394 395 /// <summary> 396 /// Smoothly adjusts <see cref="Drawable.X"/> over time. 397 /// </summary> 398 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 399 public static TransformSequence<T> MoveToX<T>(this T drawable, float destination, double duration = 0, Easing easing = Easing.None) 400 where T : Drawable 401 => drawable.MoveToX(destination, duration, new DefaultEasingFunction(easing)); 402 403 /// <summary> 404 /// Smoothly adjusts <see cref="Drawable.Y"/> over time. 405 /// </summary> 406 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 407 public static TransformSequence<T> MoveToY<T>(this T drawable, float destination, double duration = 0, Easing easing = Easing.None) 408 where T : Drawable 409 => drawable.MoveToY(destination, duration, new DefaultEasingFunction(easing)); 410 411 /// <summary> 412 /// Smoothly adjusts <see cref="Drawable.Position"/> by an offset to its final value over time. 413 /// </summary> 414 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 415 public static TransformSequence<T> MoveToOffset<T>(this T drawable, Vector2 offset, double duration = 0, Easing easing = Easing.None) 416 where T : Drawable 417 => drawable.MoveToOffset(offset, duration, new DefaultEasingFunction(easing)); 418 419 /// <summary> 420 /// Smoothly adjusts <see cref="IContainer.RelativeChildSize"/> over time. 421 /// </summary> 422 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 423 public static TransformSequence<T> TransformRelativeChildSizeTo<T>(this T container, Vector2 newSize, double duration = 0, Easing easing = Easing.None) 424 where T : class, IContainer 425 => container.TransformRelativeChildSizeTo(newSize, duration, new DefaultEasingFunction(easing)); 426 427 /// <summary> 428 /// Smoothly adjusts <see cref="IContainer.RelativeChildOffset"/> over time. 429 /// </summary> 430 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 431 public static TransformSequence<T> TransformRelativeChildOffsetTo<T>(this T container, Vector2 newOffset, double duration = 0, Easing easing = Easing.None) 432 where T : class, IContainer 433 => container.TransformRelativeChildOffsetTo(newOffset, duration, new DefaultEasingFunction(easing)); 434 435 /// <summary> 436 /// Smoothly adjusts <see cref="IBufferedContainer.BlurSigma"/> over time. 437 /// </summary> 438 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 439 public static TransformSequence<T> BlurTo<T>(this T bufferedContainer, Vector2 newBlurSigma, double duration = 0, Easing easing = Easing.None) 440 where T : class, IBufferedContainer 441 => bufferedContainer.BlurTo(newBlurSigma, duration, new DefaultEasingFunction(easing)); 442 443 /// <summary> 444 /// Smoothly adjusts <see cref="IFillFlowContainer.Spacing"/> over time. 445 /// </summary> 446 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 447 public static TransformSequence<T> TransformSpacingTo<T>(this T flowContainer, Vector2 newSpacing, double duration = 0, Easing easing = Easing.None) 448 where T : class, IFillFlowContainer 449 => flowContainer.TransformSpacingTo(newSpacing, duration, new DefaultEasingFunction(easing)); 450 451 /// <summary> 452 /// Smoothly adjusts the alpha channel of the colour of <see cref="IContainer.EdgeEffect"/> over time. 453 /// </summary> 454 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 455 public static TransformSequence<T> FadeEdgeEffectTo<T>(this T container, float newAlpha, double duration = 0, Easing easing = Easing.None) 456 where T : class, IContainer 457 => container.FadeEdgeEffectTo(newAlpha, duration, new DefaultEasingFunction(easing)); 458 459 /// <summary> 460 /// Smoothly adjusts the colour of <see cref="IContainer.EdgeEffect"/> over time. 461 /// </summary> 462 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 463 public static TransformSequence<T> FadeEdgeEffectTo<T>(this T container, Color4 newColour, double duration = 0, Easing easing = Easing.None) 464 where T : class, IContainer 465 => container.FadeEdgeEffectTo(newColour, duration, new DefaultEasingFunction(easing)); 466 467 /// <summary> 468 /// Smoothly adjusts all parameters of <see cref="IContainer.EdgeEffect"/> over time. 469 /// </summary> 470 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 471 public static TransformSequence<T> TweenEdgeEffectTo<T>(this T container, EdgeEffectParameters newParameters, double duration = 0, Easing easing = Easing.None) 472 where T : class, IContainer 473 => container.TweenEdgeEffectTo(newParameters, duration, new DefaultEasingFunction(easing)); 474 475 /// <summary> 476 /// Smoothly adjusts the value of a <see cref="Bindable{TValue}"/> over time. 477 /// </summary> 478 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 479 public static TransformSequence<T> TransformBindableTo<T, TValue>(this T drawable, [NotNull] Bindable<TValue> bindable, TValue newValue, double duration = 0, Easing easing = Easing.None) 480 where T : class, ITransformable 481 => drawable.TransformBindableTo(bindable, newValue, duration, new DefaultEasingFunction(easing)); 482 483 #endregion 484 485 #region Generic Easing 486 487 /// <summary> 488 /// Smoothly adjusts <see cref="Drawable.Alpha"/> to 1 over time. 489 /// </summary> 490 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 491 public static TransformSequence<T> FadeIn<T, TEasing>(this T drawable, double duration, in TEasing easing) 492 where T : Drawable 493 where TEasing : IEasingFunction 494 => drawable.FadeTo(1, duration, easing); 495 496 /// <summary> 497 /// Smoothly adjusts <see cref="Drawable.Alpha"/> from 0 to 1 over time. 498 /// </summary> 499 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 500 public static TransformSequence<T> FadeInFromZero<T, TEasing>(this T drawable, double duration, in TEasing easing) 501 where T : Drawable 502 where TEasing : IEasingFunction 503 => drawable.FadeTo(0).FadeIn(duration, easing); 504 505 /// <summary> 506 /// Smoothly adjusts <see cref="Drawable.Alpha"/> to 0 over time. 507 /// </summary> 508 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 509 public static TransformSequence<T> FadeOut<T, TEasing>(this T drawable, double duration, in TEasing easing) 510 where T : Drawable 511 where TEasing : IEasingFunction 512 => drawable.FadeTo(0, duration, easing); 513 514 /// <summary> 515 /// Smoothly adjusts <see cref="Drawable.Alpha"/> from 1 to 0 over time. 516 /// </summary> 517 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 518 public static TransformSequence<T> FadeOutFromOne<T, TEasing>(this T drawable, double duration, in TEasing easing) 519 where T : Drawable 520 where TEasing : IEasingFunction 521 => drawable.FadeTo(1).FadeOut(duration, easing); 522 523 /// <summary> 524 /// Smoothly adjusts <see cref="Drawable.Alpha"/> over time. 525 /// </summary> 526 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 527 public static TransformSequence<T> FadeTo<T, TEasing>(this T drawable, float newAlpha, double duration, in TEasing easing) 528 where T : Drawable 529 where TEasing : IEasingFunction 530 => drawable.TransformTo(nameof(drawable.Alpha), newAlpha, duration, easing); 531 532 /// <summary> 533 /// Smoothly adjusts <see cref="Drawable.Colour"/> over time. 534 /// </summary> 535 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 536 public static TransformSequence<T> FadeColour<T, TEasing>(this T drawable, ColourInfo newColour, double duration, in TEasing easing) 537 where T : Drawable 538 where TEasing : IEasingFunction 539 => drawable.TransformTo(nameof(drawable.Colour), newColour, duration, easing); 540 541 /// <summary> 542 /// Instantaneously flashes <see cref="Drawable.Colour"/>, then smoothly changes it back over time. 543 /// </summary> 544 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 545 public static TransformSequence<T> FlashColour<T, TEasing>(this T drawable, ColourInfo flashColour, double duration, in TEasing easing) 546 where T : Drawable 547 where TEasing : IEasingFunction 548 { 549 ColourInfo endValue = (drawable.Transforms.LastOrDefault(t => t.TargetMember == nameof(drawable.Colour)) as Transform<ColourInfo>)?.EndValue ?? drawable.Colour; 550 return drawable.FadeColour(flashColour).FadeColour(endValue, duration, easing); 551 } 552 553 /// <summary> 554 /// Smoothly adjusts <see cref="Drawable.Rotation"/> over time. 555 /// </summary> 556 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 557 public static TransformSequence<T> RotateTo<T, TEasing>(this T drawable, float newRotation, double duration, in TEasing easing) 558 where T : Drawable 559 where TEasing : IEasingFunction 560 => drawable.TransformTo(nameof(drawable.Rotation), newRotation, duration, easing); 561 562 /// <summary> 563 /// Smoothly adjusts <see cref="Drawable.Scale"/> over time. 564 /// </summary> 565 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 566 public static TransformSequence<T> ScaleTo<T, TEasing>(this T drawable, float newScale, double duration, in TEasing easing) 567 where T : Drawable 568 where TEasing : IEasingFunction 569 => drawable.ScaleTo(new Vector2(newScale), duration, easing); 570 571 /// <summary> 572 /// Smoothly adjusts <see cref="Drawable.Scale"/> over time. 573 /// </summary> 574 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 575 public static TransformSequence<T> ScaleTo<T, TEasing>(this T drawable, Vector2 newScale, double duration, in TEasing easing) 576 where T : Drawable 577 where TEasing : IEasingFunction 578 => drawable.TransformTo(nameof(drawable.Scale), newScale, duration, easing); 579 580 /// <summary> 581 /// Smoothly adjusts <see cref="Drawable.Size"/> over time. 582 /// </summary> 583 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 584 public static TransformSequence<T> ResizeTo<T, TEasing>(this T drawable, float newSize, double duration, in TEasing easing) 585 where T : Drawable 586 where TEasing : IEasingFunction 587 => drawable.ResizeTo(new Vector2(newSize), duration, easing); 588 589 /// <summary> 590 /// Smoothly adjusts <see cref="Drawable.Size"/> over time. 591 /// </summary> 592 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 593 public static TransformSequence<T> ResizeTo<T, TEasing>(this T drawable, Vector2 newSize, double duration, in TEasing easing) 594 where T : Drawable 595 where TEasing : IEasingFunction 596 => drawable.TransformTo(nameof(drawable.Size), newSize, duration, easing); 597 598 /// <summary> 599 /// Smoothly adjusts <see cref="Drawable.Width"/> over time. 600 /// </summary> 601 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 602 public static TransformSequence<T> ResizeWidthTo<T, TEasing>(this T drawable, float newWidth, double duration, in TEasing easing) 603 where T : Drawable 604 where TEasing : IEasingFunction 605 => drawable.TransformTo(nameof(drawable.Width), newWidth, duration, easing, nameof(drawable.Size)); 606 607 /// <summary> 608 /// Smoothly adjusts <see cref="Drawable.Height"/> over time. 609 /// </summary> 610 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 611 public static TransformSequence<T> ResizeHeightTo<T, TEasing>(this T drawable, float newHeight, double duration, in TEasing easing) 612 where T : Drawable 613 where TEasing : IEasingFunction 614 => drawable.TransformTo(nameof(drawable.Height), newHeight, duration, easing, nameof(drawable.Size)); 615 616 /// <summary> 617 /// Smoothly adjusts <see cref="Drawable.Position"/> over time. 618 /// </summary> 619 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 620 public static TransformSequence<T> MoveTo<T, TEasing>(this T drawable, Vector2 newPosition, double duration, in TEasing easing) 621 where T : Drawable 622 where TEasing : IEasingFunction 623 => drawable.TransformTo(nameof(drawable.Position), newPosition, duration, easing); 624 625 /// <summary> 626 /// Smoothly adjusts <see cref="Drawable.X"/> or <see cref="Drawable.Y"/> over time. 627 /// </summary> 628 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 629 public static TransformSequence<T> MoveTo<T, TEasing>(this T drawable, Direction direction, float destination, double duration, in TEasing easing) 630 where T : Drawable 631 where TEasing : IEasingFunction 632 { 633 switch (direction) 634 { 635 case Direction.Horizontal: 636 return drawable.MoveToX(destination, duration, easing); 637 638 case Direction.Vertical: 639 return drawable.MoveToY(destination, duration, easing); 640 } 641 642 throw new InvalidOperationException($"Invalid direction ({direction}) passed to {nameof(MoveTo)}."); 643 } 644 645 /// <summary> 646 /// Smoothly adjusts <see cref="Drawable.X"/> over time. 647 /// </summary> 648 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 649 public static TransformSequence<T> MoveToX<T, TEasing>(this T drawable, float destination, double duration, in TEasing easing) 650 where T : Drawable 651 where TEasing : IEasingFunction 652 => drawable.TransformTo(nameof(drawable.X), destination, duration, easing, nameof(drawable.Position)); 653 654 /// <summary> 655 /// Smoothly adjusts <see cref="Drawable.Y"/> over time. 656 /// </summary> 657 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 658 public static TransformSequence<T> MoveToY<T, TEasing>(this T drawable, float destination, double duration, in TEasing easing) 659 where T : Drawable 660 where TEasing : IEasingFunction 661 => drawable.TransformTo(nameof(drawable.Y), destination, duration, easing, nameof(drawable.Position)); 662 663 /// <summary> 664 /// Smoothly adjusts <see cref="Drawable.Position"/> by an offset to its final value over time. 665 /// </summary> 666 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 667 public static TransformSequence<T> MoveToOffset<T, TEasing>(this T drawable, Vector2 offset, double duration, in TEasing easing) 668 where T : Drawable 669 where TEasing : IEasingFunction 670 => drawable.TransformTo(drawable.PopulateTransform(new PositionOffsetTransform<TEasing>(offset), default, duration, easing)); 671 672 /// <summary> 673 /// Smoothly adjusts <see cref="IContainer.RelativeChildSize"/> over time. 674 /// </summary> 675 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 676 public static TransformSequence<T> TransformRelativeChildSizeTo<T, TEasing>(this T container, Vector2 newSize, double duration, in TEasing easing) 677 where T : class, IContainer 678 where TEasing : IEasingFunction 679 => container.TransformTo(nameof(container.RelativeChildSize), newSize, duration, easing); 680 681 /// <summary> 682 /// Smoothly adjusts <see cref="IContainer.RelativeChildOffset"/> over time. 683 /// </summary> 684 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 685 public static TransformSequence<T> TransformRelativeChildOffsetTo<T, TEasing>(this T container, Vector2 newOffset, double duration, in TEasing easing) 686 where T : class, IContainer 687 where TEasing : IEasingFunction 688 => container.TransformTo(nameof(container.RelativeChildOffset), newOffset, duration, easing); 689 690 /// <summary> 691 /// Smoothly adjusts <see cref="IBufferedContainer.BlurSigma"/> over time. 692 /// </summary> 693 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 694 public static TransformSequence<T> BlurTo<T, TEasing>(this T bufferedContainer, Vector2 newBlurSigma, double duration, in TEasing easing) 695 where T : class, IBufferedContainer 696 where TEasing : IEasingFunction 697 => bufferedContainer.TransformTo(nameof(bufferedContainer.BlurSigma), newBlurSigma, duration, easing); 698 699 /// <summary> 700 /// Smoothly adjusts <see cref="IFillFlowContainer.Spacing"/> over time. 701 /// </summary> 702 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 703 public static TransformSequence<T> TransformSpacingTo<T, TEasing>(this T flowContainer, Vector2 newSpacing, double duration, in TEasing easing) 704 where T : class, IFillFlowContainer 705 where TEasing : IEasingFunction 706 => flowContainer.TransformTo(nameof(flowContainer.Spacing), newSpacing, duration, easing); 707 708 /// <summary> 709 /// Smoothly adjusts the alpha channel of the colour of <see cref="IContainer.EdgeEffect"/> over time. 710 /// </summary> 711 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 712 public static TransformSequence<T> FadeEdgeEffectTo<T, TEasing>(this T container, float newAlpha, double duration, in TEasing easing) 713 where T : class, IContainer 714 where TEasing : IEasingFunction 715 { 716 Color4 targetColour = container.EdgeEffect.Colour; 717 targetColour.A = newAlpha; 718 return container.FadeEdgeEffectTo(targetColour, duration, easing); 719 } 720 721 /// <summary> 722 /// Smoothly adjusts the colour of <see cref="IContainer.EdgeEffect"/> over time. 723 /// </summary> 724 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 725 public static TransformSequence<T> FadeEdgeEffectTo<T, TEasing>(this T container, Color4 newColour, double duration, in TEasing easing) 726 where T : class, IContainer 727 where TEasing : IEasingFunction 728 { 729 var effect = container.EdgeEffect; 730 effect.Colour = newColour; 731 return container.TweenEdgeEffectTo(effect, duration, easing); 732 } 733 734 /// <summary> 735 /// Smoothly adjusts all parameters of <see cref="IContainer.EdgeEffect"/> over time. 736 /// </summary> 737 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 738 public static TransformSequence<T> TweenEdgeEffectTo<T, TEasing>(this T container, EdgeEffectParameters newParameters, double duration, in TEasing easing) 739 where T : class, IContainer 740 where TEasing : IEasingFunction 741 => container.TransformTo(nameof(container.EdgeEffect), newParameters, duration, easing); 742 743 /// <summary> 744 /// Smoothly adjusts the value of a <see cref="Bindable{TValue}"/> over time. 745 /// </summary> 746 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 747 public static TransformSequence<T> TransformBindableTo<T, TValue, TEasing>(this T drawable, [NotNull] Bindable<TValue> bindable, TValue newValue, double duration, in TEasing easing) 748 where T : class, ITransformable 749 where TEasing : IEasingFunction 750 => drawable.TransformTo(drawable.PopulateTransform(new TransformBindable<TValue, TEasing, T>(bindable), newValue, duration, easing)); 751 752 #endregion 753 754 private class PositionOffsetTransform<TEasing> : Transform<Vector2, TEasing, Drawable> 755 where TEasing : IEasingFunction 756 { 757 private readonly Vector2 offset; 758 759 public override string TargetMember => nameof(Drawable.Position); 760 761 public PositionOffsetTransform(Vector2 offset) 762 { 763 this.offset = offset; 764 } 765 766 private Vector2 positionAt(double time) 767 { 768 if (time < StartTime) return StartValue; 769 if (time >= EndTime) return EndValue; 770 771 return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing); 772 } 773 774 protected override void Apply(Drawable d, double time) => d.Position = positionAt(time); 775 776 protected override void ReadIntoStartValue(Drawable d) 777 { 778 StartValue = d.Position; 779 EndValue = d.Position + offset; 780 } 781 } 782 } 783}