···2929 /// <param name="easing">The transform easing to be used for tweening.</param>
3030 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
3131 public static TransformSequence<TThis> TransformTo<TThis, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration = 0, Easing easing = Easing.None)
3232- where TThis : class, ITransformable =>
3333- t.TransformTo(t.MakeTransform(propertyOrFieldName, newValue, duration, easing));
3232+ where TThis : class, ITransformable
3333+ => t.TransformTo(t.MakeTransform(propertyOrFieldName, newValue, duration, new DefaultEasingFunction(easing)));
3434+3535+ /// <summary>
3636+ /// Transforms a given property or field member of a given <see cref="ITransformable"/> <typeparamref name="TThis"/> to <paramref name="newValue"/>.
3737+ /// The value of the given member is smoothly changed over time using the given <paramref name="easing"/> for tweening.
3838+ /// </summary>
3939+ /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> to apply the <see cref="Transform{TValue, T}"/> to.</typeparam>
4040+ /// <typeparam name="TValue">The value type which is being transformed.</typeparam>
4141+ /// <typeparam name="TEasing">The type of easing.</typeparam>
4242+ /// <param name="t">The <see cref="ITransformable"/> to apply the <see cref="Transform{TValue, T}"/> to.</param>
4343+ /// <param name="propertyOrFieldName">The property or field name of the member ot <typeparamref name="TThis"/> to transform.</param>
4444+ /// <param name="newValue">The value to transform to.</param>
4545+ /// <param name="duration">The transform duration.</param>
4646+ /// <param name="easing">The transform easing to be used for tweening.</param>
4747+ /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
4848+ public static TransformSequence<TThis> TransformTo<TThis, TValue, TEasing>(this TThis t, string propertyOrFieldName, TValue newValue, double duration, TEasing easing)
4949+ where TThis : class, ITransformable
5050+ where TEasing : IEasingFunction
5151+ => t.TransformTo(t.MakeTransform(propertyOrFieldName, newValue, duration, easing));
34523553 /// <summary>
3654 /// Applies a <see cref="Transform"/> to a given <see cref="ITransformable"/>.
···5068 /// <summary>
5169 /// Creates a <see cref="Transform{TValue, T}"/> for smoothly changing <paramref name="propertyOrFieldName"/>
5270 /// over time using the given <paramref name="easing"/> for tweening.
5353- /// <see cref="PopulateTransform{TValue, TThis}(TThis, Transform{TValue, TThis}, TValue, double, Easing)"/>
5454- /// is invoked as part of this method.
7171+ /// <see cref="PopulateTransform{TValue, DefaultEasingFunction, TThis}"/> is invoked as part of this method.
7272+ /// </summary>
7373+ /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam>
7474+ /// <typeparam name="TValue">The value type which is being transformed.</typeparam>
7575+ /// <param name="t">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param>
7676+ /// <param name="propertyOrFieldName">The property or field name of the member ot <typeparamref name="TThis"/> to transform.</param>
7777+ /// <param name="newValue">The value to transform to.</param>
7878+ /// <param name="duration">The transform duration.</param>
7979+ /// <param name="easing">The transform easing to be used for tweening.</param>
8080+ /// <returns>The resulting <see cref="Transform{TValue, T}"/>.</returns>
8181+ public static Transform<TValue, DefaultEasingFunction, TThis> MakeTransform<TThis, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration = 0,
8282+ Easing easing = Easing.None)
8383+ where TThis : class, ITransformable
8484+ => t.MakeTransform(propertyOrFieldName, newValue, duration, new DefaultEasingFunction(easing));
8585+8686+ /// <summary>
8787+ /// Creates a <see cref="Transform{TValue, T}"/> for smoothly changing <paramref name="propertyOrFieldName"/>
8888+ /// over time using the given <paramref name="easing"/> for tweening.
8989+ /// <see cref="PopulateTransform{TValue, TEasing, TThis}"/> is invoked as part of this method.
5590 /// </summary>
5691 /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam>
5792 /// <typeparam name="TValue">The value type which is being transformed.</typeparam>
9393+ /// <typeparam name="TEasing">The type of easing.</typeparam>
5894 /// <param name="t">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param>
5995 /// <param name="propertyOrFieldName">The property or field name of the member ot <typeparamref name="TThis"/> to transform.</param>
6096 /// <param name="newValue">The value to transform to.</param>
6197 /// <param name="duration">The transform duration.</param>
6298 /// <param name="easing">The transform easing to be used for tweening.</param>
6399 /// <returns>The resulting <see cref="Transform{TValue, T}"/>.</returns>
6464- public static Transform<TValue, TThis> MakeTransform<TThis, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration = 0, Easing easing = Easing.None)
6565- where TThis : class, ITransformable =>
6666- t.PopulateTransform(new TransformCustom<TValue, TThis>(propertyOrFieldName), newValue, duration, easing);
100100+ public static Transform<TValue, TEasing, TThis> MakeTransform<TThis, TEasing, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration, TEasing easing)
101101+ where TThis : class, ITransformable
102102+ where TEasing : IEasingFunction
103103+ => t.PopulateTransform(new TransformCustom<TValue, TEasing, TThis>(propertyOrFieldName), newValue, duration, easing);
6710468105 /// <summary>
69106 /// Populates a newly created <see cref="Transform{TValue, T}"/> with necessary values.
···77114 /// <param name="duration">The transform duration.</param>
78115 /// <param name="easing">The transform easing to be used for tweening.</param>
79116 /// <returns>The populated <paramref name="transform"/>.</returns>
8080- public static Transform<TValue, TThis> PopulateTransform<TValue, TThis>(this TThis t, Transform<TValue, TThis> transform, TValue newValue, double duration = 0, Easing easing = Easing.None)
117117+ public static Transform<TValue, DefaultEasingFunction, TThis> PopulateTransform<TValue, TThis>(this TThis t, Transform<TValue, DefaultEasingFunction, TThis> transform, TValue newValue,
118118+ double duration = 0, Easing easing = Easing.None)
81119 where TThis : class, ITransformable
120120+ => t.PopulateTransform(transform, newValue, duration, new DefaultEasingFunction(easing));
121121+122122+ /// <summary>
123123+ /// Populates a newly created <see cref="Transform{TValue, T}"/> with necessary values.
124124+ /// All <see cref="Transform{TValue, T}"/>s must be populated by this method prior to being used.
125125+ /// </summary>
126126+ /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam>
127127+ /// <typeparam name="TValue">The value type which is being transformed.</typeparam>
128128+ /// <typeparam name="TEasing">The type of easing.</typeparam>
129129+ /// <param name="t">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param>
130130+ /// <param name="transform">The transform to populate.</param>
131131+ /// <param name="newValue">The value to transform to.</param>
132132+ /// <param name="duration">The transform duration.</param>
133133+ /// <param name="easing">The transform easing to be used for tweening.</param>
134134+ /// <returns>The populated <paramref name="transform"/>.</returns>
135135+ public static Transform<TValue, TEasing, TThis> PopulateTransform<TValue, TEasing, TThis>(this TThis t, Transform<TValue, TEasing, TThis> transform, TValue newValue, double duration,
136136+ TEasing easing)
137137+ where TThis : class, ITransformable
138138+ where TEasing : IEasingFunction
82139 {
83140 if (duration < 0)
84141 throw new ArgumentOutOfRangeException(nameof(duration), $"{nameof(duration)} must be positive.");
···415472 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
416473 public static TransformSequence<T> TransformBindableTo<T, TValue>(this T drawable, [NotNull] Bindable<TValue> bindable, TValue newValue, double duration = 0, Easing easing = Easing.None)
417474 where T : class, ITransformable =>
418418- drawable.TransformTo(drawable.PopulateTransform(new TransformBindable<TValue, T>(bindable), newValue, duration, easing));
475475+ drawable.TransformTo(drawable.PopulateTransform(new TransformBindable<TValue, DefaultEasingFunction, T>(bindable), newValue, duration, new DefaultEasingFunction(easing)));
419476 }
420477}
+9-3
osu.Framework/Graphics/Transforms/Transform.cs
···2626 /// </summary>
2727 public bool Rewindable = true;
28282929- public Easing Easing;
3030-3129 public abstract ITransformable TargetTransformable { get; }
32303331 public double StartTime { get; internal set; }
···7573 public TValue EndValue { get; protected internal set; }
7674 }
77757878- public abstract class Transform<TValue, T> : Transform<TValue>
7676+ public abstract class Transform<TValue, TEasing, T> : Transform<TValue>
7777+ where TEasing : IEasingFunction
7978 where T : class, ITransformable
8079 {
8180 public override ITransformable TargetTransformable => Target;
82818382 public T Target { get; internal set; }
8383+8484+ public TEasing Easing { get; internal set; }
84858586 public sealed override void Apply(double time)
8687 {
···9596 protected abstract void ReadIntoStartValue(T d);
96979798 public override string ToString() => $"{Target.GetType().Name}.{TargetMember} {StartTime}-{EndTime}ms {StartValue} -> {EndValue}";
9999+ }
100100+101101+ public abstract class Transform<TValue, T> : Transform<TValue, DefaultEasingFunction, T>
102102+ where T : class, ITransformable
103103+ {
98104 }
99105}
···1515 /// A transform which operates on arbitrary fields or properties of a given target.
1616 /// </summary>
1717 /// <typeparam name="TValue">The type of the field or property to operate upon.</typeparam>
1818+ /// <typeparam name="TEasing">The type of easing.</typeparam>
1819 /// <typeparam name="T">The type of the target to operate upon.</typeparam>
1919- internal class TransformCustom<TValue, T> : Transform<TValue, T> where T : class, ITransformable
2020+ internal class TransformCustom<TValue, TEasing, T> : Transform<TValue, TEasing, T>
2121+ where T : class, ITransformable
2222+ where TEasing : IEasingFunction
2023 {
2124 private delegate TValue ReadFunc(T transformable);
2225···141144 private static Accessor getAccessor(string propertyOrFieldName) => accessors.GetOrAdd(propertyOrFieldName, key => findAccessor(typeof(T), key));
142145143146 private readonly Accessor accessor;
144144- private readonly InterpolationFunc<TValue> interpolationFunc;
147147+ private readonly InterpolationFunc<TValue, TEasing> interpolationFunc;
145148146149 /// <summary>
147150 /// Creates a new instance operating on a property or field of <typeparamref name="T"/>. The property or field is
···175178 protected override void Apply(T d, double time) => accessor.Write(d, valueAt(time));
176179177180 protected override void ReadIntoStartValue(T d) => StartValue = accessor.Read(d);
181181+ }
182182+183183+ internal class TransformCustom<TValue, T> : TransformCustom<TValue, DefaultEasingFunction, T>
184184+ where T : class, ITransformable
185185+ {
186186+ public TransformCustom(string propertyOrFieldName)
187187+ : base(propertyOrFieldName)
188188+ {
189189+ }
178190 }
179191}
···412412413413 /// <summary>
414414 /// Adds to this object a <see cref="Transform"/> which was previously populated using this object via
415415- /// <see cref="TransformableExtensions.PopulateTransform{TValue, TThis}(TThis, Transform{TValue, TThis}, TValue, double, Easing)"/>.
415415+ /// <see cref="TransformableExtensions.PopulateTransform{TValue, TEasing, TThis}"/>.
416416 /// Added <see cref="Transform"/>s are immediately applied, and therefore have an immediate effect on this object if the current time of this
417417 /// object falls within <see cref="Transform.StartTime"/> and <see cref="Transform.EndTime"/>.
418418 /// If <see cref="Clock"/> is null, e.g. because this object has just been constructed, then the given transform will be finished instantaneously.
+3-3
osu.Framework/Utils/IInterpolable.cs
···11// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
22// See the LICENCE file in the repository root for full licence text.
3344-using osu.Framework.Graphics;
44+using osu.Framework.Graphics.Transforms;
5566namespace osu.Framework.Utils
77{
···2222 /// <param name="endValue">The <typeparamref name="TValue"/> at <paramref name="time"/> = <paramref name="endTime"/>.</param>
2323 /// <param name="startTime">The start time.</param>
2424 /// <param name="endTime">The end time.</param>
2525- /// <param name="easingType">The easing to use.</param>
2525+ /// <param name="easing">The easing function to use.</param>
2626 /// <returns>The interpolated value.</returns>
2727- TValue ValueAt(double time, TValue startValue, TValue endValue, double startTime, double endTime, Easing easingType = Easing.None);
2727+ TValue ValueAt<TEasing>(double time, TValue startValue, TValue endValue, double startTime, double endTime, in TEasing easing) where TEasing : IEasingFunction;
2828 }
2929}
+8-7
osu.Framework/Utils/Interpolation.cs
···330330331331 public static TValue ValueAt<TValue, TEasing>(double time, TValue startValue, TValue endValue, double startTime, double endTime, in TEasing easing)
332332 where TEasing : IEasingFunction
333333- => GenericInterpolation<TValue>.FUNCTION(time, startValue, endValue, startTime, endTime, easing);
333333+ => GenericInterpolation<TValue, TEasing>.FUNCTION(time, startValue, endValue, startTime, endTime, easing);
334334335335 #endregion
336336···341341 where TEasing : IEasingFunction
342342 => easing.ApplyEasing(time);
343343344344- private static class GenericInterpolation<TValue>
344344+ private static class GenericInterpolation<TValue, TEasing>
345345+ where TEasing : IEasingFunction
345346 {
346346- public static readonly InterpolationFunc<TValue> FUNCTION;
347347+ public static readonly InterpolationFunc<TValue, TEasing> FUNCTION;
347348348349 static GenericInterpolation()
349350 {
350351 const string interpolation_method = nameof(Interpolation.ValueAt);
351352352352- var parameters = typeof(InterpolationFunc<TValue>)
353353- .GetMethod(nameof(InterpolationFunc<TValue>.Invoke))
353353+ var parameters = typeof(InterpolationFunc<TValue, TEasing>)
354354+ .GetMethod(nameof(InterpolationFunc<TValue, TEasing>.Invoke))
354355 ?.GetParameters().Select(p => p.ParameterType).ToArray();
355356356357 MethodInfo valueAtMethod = typeof(Interpolation).GetMethod(interpolation_method, parameters);
357358358359 if (valueAtMethod != null)
359359- FUNCTION = (InterpolationFunc<TValue>)valueAtMethod.CreateDelegate(typeof(InterpolationFunc<TValue>));
360360+ FUNCTION = (InterpolationFunc<TValue, TEasing>)valueAtMethod.CreateDelegate(typeof(InterpolationFunc<TValue, TEasing>));
360361 else
361362 {
362363 var typeRef = FormatterServices.GetSafeUninitializedObject(typeof(TValue)) as IInterpolable<TValue>;
···370371 }
371372 }
372373373373- public delegate TValue InterpolationFunc<TValue>(double time, TValue startValue, TValue endValue, double startTime, double endTime, Easing easingType);
374374+ public delegate TValue InterpolationFunc<TValue, TEasing>(double time, TValue startValue, TValue endValue, double startTime, double endTime, in TEasing easingType) where TEasing : IEasingFunction;
374375}