committed by
GitHub
11 changed files with 548 additions and 51 deletions
@ -0,0 +1,123 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
using Avalonia.Data; |
|||
using Avalonia.Media; |
|||
using Avalonia.Media.Immutable; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Animation.Animators |
|||
{ |
|||
/// <summary>
|
|||
/// Animator that handles <see cref="SolidColorBrush"/> values.
|
|||
/// </summary>
|
|||
public class GradientBrushAnimator : Animator<IGradientBrush?> |
|||
{ |
|||
private static readonly RelativePointAnimator s_relativePointAnimator = new RelativePointAnimator(); |
|||
private static readonly DoubleAnimator s_doubleAnimator = new DoubleAnimator(); |
|||
|
|||
public override IGradientBrush? Interpolate(double progress, IGradientBrush? oldValue, IGradientBrush? newValue) |
|||
{ |
|||
if (oldValue is null || newValue is null) |
|||
{ |
|||
return progress >= 0.5 ? newValue : oldValue; |
|||
} |
|||
|
|||
switch (oldValue) |
|||
{ |
|||
case IRadialGradientBrush oldRadial when newValue is IRadialGradientBrush newRadial: |
|||
return new ImmutableRadialGradientBrush( |
|||
InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), |
|||
s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), |
|||
oldValue.SpreadMethod, |
|||
s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center), |
|||
s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin), |
|||
s_doubleAnimator.Interpolate(progress, oldRadial.Radius, newRadial.Radius)); |
|||
|
|||
case IConicGradientBrush oldConic when newValue is IConicGradientBrush newConic: |
|||
return new ImmutableConicGradientBrush( |
|||
InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), |
|||
s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), |
|||
oldValue.SpreadMethod, |
|||
s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center), |
|||
s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle)); |
|||
|
|||
case ILinearGradientBrush oldLinear when newValue is ILinearGradientBrush newLinear: |
|||
return new ImmutableLinearGradientBrush( |
|||
InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), |
|||
s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), |
|||
oldValue.SpreadMethod, |
|||
s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint), |
|||
s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint)); |
|||
|
|||
default: |
|||
return progress >= 0.5 ? newValue : oldValue; |
|||
} |
|||
} |
|||
|
|||
public override IDisposable BindAnimation(Animatable control, IObservable<IGradientBrush?> instance) |
|||
{ |
|||
return control.Bind((AvaloniaProperty<IBrush?>)Property, instance, BindingPriority.Animation); |
|||
} |
|||
|
|||
private IReadOnlyList<ImmutableGradientStop> InterpolateStops(double progress, IReadOnlyList<IGradientStop> oldValue, IReadOnlyList<IGradientStop> newValue) |
|||
{ |
|||
var resultCount = Math.Max(oldValue.Count, newValue.Count); |
|||
var stops = new ImmutableGradientStop[resultCount]; |
|||
|
|||
for (int index = 0, oldIndex = 0, newIndex = 0; index < resultCount; index++) |
|||
{ |
|||
stops[index] = new ImmutableGradientStop( |
|||
s_doubleAnimator.Interpolate(progress, oldValue[oldIndex].Offset, newValue[newIndex].Offset), |
|||
ColorAnimator.InterpolateCore(progress, oldValue[oldIndex].Color, newValue[newIndex].Color)); |
|||
|
|||
if (oldIndex < oldValue.Count - 1) |
|||
{ |
|||
oldIndex++; |
|||
} |
|||
|
|||
if (newIndex < newValue.Count - 1) |
|||
{ |
|||
newIndex++; |
|||
} |
|||
} |
|||
|
|||
return stops; |
|||
} |
|||
|
|||
internal static IGradientBrush ConvertSolidColorBrushToGradient(IGradientBrush gradientBrush, ISolidColorBrush solidColorBrush) |
|||
{ |
|||
switch (gradientBrush) |
|||
{ |
|||
case IRadialGradientBrush oldRadial: |
|||
return new ImmutableRadialGradientBrush( |
|||
CreateStopsFromSolidColorBrush(solidColorBrush, oldRadial.GradientStops), solidColorBrush.Opacity, |
|||
oldRadial.SpreadMethod, oldRadial.Center, oldRadial.GradientOrigin, oldRadial.Radius); |
|||
|
|||
case IConicGradientBrush oldConic: |
|||
return new ImmutableConicGradientBrush( |
|||
CreateStopsFromSolidColorBrush(solidColorBrush, oldConic.GradientStops), solidColorBrush.Opacity, |
|||
oldConic.SpreadMethod, oldConic.Center, oldConic.Angle); |
|||
|
|||
case ILinearGradientBrush oldLinear: |
|||
return new ImmutableLinearGradientBrush( |
|||
CreateStopsFromSolidColorBrush(solidColorBrush, oldLinear.GradientStops), solidColorBrush.Opacity, |
|||
oldLinear.SpreadMethod, oldLinear.StartPoint, oldLinear.EndPoint); |
|||
|
|||
default: |
|||
throw new NotSupportedException($"Gradient of type {gradientBrush?.GetType()} is not supported"); |
|||
} |
|||
|
|||
static IReadOnlyList<ImmutableGradientStop> CreateStopsFromSolidColorBrush(ISolidColorBrush solidColorBrush, IReadOnlyList<IGradientStop> baseStops) |
|||
{ |
|||
var stops = new ImmutableGradientStop[baseStops.Count]; |
|||
for (int index = 0; index < baseStops.Count; index++) |
|||
{ |
|||
stops[index] = new ImmutableGradientStop(baseStops[index].Offset, solidColorBrush.Color); |
|||
} |
|||
return stops; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
namespace Avalonia.Animation.Animators |
|||
{ |
|||
/// <summary>
|
|||
/// Animator that handles <see cref="RelativePoint"/> properties.
|
|||
/// </summary>
|
|||
public class RelativePointAnimator : Animator<RelativePoint> |
|||
{ |
|||
private static readonly PointAnimator s_pointAnimator = new PointAnimator(); |
|||
|
|||
public override RelativePoint Interpolate(double progress, RelativePoint oldValue, RelativePoint newValue) |
|||
{ |
|||
if (oldValue.Unit != newValue.Unit) |
|||
{ |
|||
return progress >= 0.5 ? newValue : oldValue; |
|||
} |
|||
|
|||
return new RelativePoint(s_pointAnimator.Interpolate(progress, oldValue.Point, newValue.Point), oldValue.Unit); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using Avalonia.Animation.Animators; |
|||
|
|||
namespace Avalonia.Animation |
|||
{ |
|||
/// <summary>
|
|||
/// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="RelativePoint"/> type.
|
|||
/// </summary>
|
|||
public class RelativePointTransition : AnimatorDrivenTransition<RelativePoint, RelativePointAnimator> |
|||
{ |
|||
} |
|||
} |
|||
Loading…
Reference in new issue