Skip to content

Commit

Permalink
Merge pull request #12716 from Actipro/feat-transition-direct-props
Browse files Browse the repository at this point in the history
Updated Transition to use direct properties via use of new TransitionBase class
  • Loading branch information
jmacato authored and grokys committed Oct 2, 2023
1 parent f7743c1 commit 0ecc683
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 43 deletions.
51 changes: 8 additions & 43 deletions src/Avalonia.Base/Animation/Transition.cs
Original file line number Diff line number Diff line change
@@ -1,65 +1,30 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Animation.Easings;

namespace Avalonia.Animation
{
/// <summary>
/// Defines how a property should be animated using a transition.
/// </summary>
public abstract class Transition<T> : AvaloniaObject, ITransition
public abstract class Transition<T> : TransitionBase
{
private AvaloniaProperty? _prop;

/// <summary>
/// Gets or sets the duration of the transition.
/// </summary>
public TimeSpan Duration { get; set; }

/// <summary>
/// Gets or sets delay before starting the transition.
/// </summary>
public TimeSpan Delay { get; set; } = TimeSpan.Zero;

/// <summary>
/// Gets the easing class to be used.
/// </summary>
public Easing Easing { get; set; } = new LinearEasing();

/// <inheritdocs/>
[DisallowNull]
public AvaloniaProperty? Property
static Transition()
{
get
{
return _prop;
}
set
{
if (!(value.PropertyType.IsAssignableFrom(typeof(T))))
throw new InvalidCastException
($"Invalid property type \"{typeof(T).Name}\" for this transition: {GetType().Name}.");

_prop = value;
}
PropertyProperty.Changed.AddClassHandler<Transition<T>>((x, e) => x.OnPropertyPropertyChanged(e));
}

AvaloniaProperty ITransition.Property
private void OnPropertyPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
get => Property ?? throw new InvalidOperationException("Transition has no property specified.");
set => Property = value;
if ((e.NewValue is AvaloniaProperty newValue) && !newValue.PropertyType.IsAssignableFrom(typeof(T)))
throw new InvalidCastException
($"Invalid property type \"{typeof(T).Name}\" for this transition: {GetType().Name}.");
}

/// <summary>
/// Apply interpolation to the property.
/// </summary>
internal abstract IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue);

/// <inheritdocs/>
IDisposable ITransition.Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
=> Apply(control, clock, oldValue, newValue);

internal virtual IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
internal override IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
{
if (Property is null)
throw new InvalidOperationException("Transition has no property specified.");
Expand Down
100 changes: 100 additions & 0 deletions src/Avalonia.Base/Animation/TransitionBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Animation.Easings;

namespace Avalonia.Animation
{
/// <summary>
/// Defines how a property should be animated using a transition.
/// </summary>
public abstract class TransitionBase : AvaloniaObject, ITransition
{
/// <summary>
/// Defines the <see cref="Duration"/> property.
/// </summary>
public static readonly DirectProperty<TransitionBase, TimeSpan> DurationProperty =
AvaloniaProperty.RegisterDirect<TransitionBase, TimeSpan>(
nameof(Duration),
o => o._duration,
(o, v) => o._duration = v);

/// <summary>
/// Defines the <see cref="Delay"/> property.
/// </summary>
public static readonly DirectProperty<TransitionBase, TimeSpan> DelayProperty =
AvaloniaProperty.RegisterDirect<TransitionBase, TimeSpan>(
nameof(Delay),
o => o._delay,
(o, v) => o._delay = v);

/// <summary>
/// Defines the <see cref="Easing"/> property.
/// </summary>
public static readonly DirectProperty<TransitionBase, Easing> EasingProperty =
AvaloniaProperty.RegisterDirect<TransitionBase, Easing>(
nameof(Easing),
o => o._easing,
(o, v) => o._easing = v);

/// <summary>
/// Defines the <see cref="Property"/> property.
/// </summary>
public static readonly DirectProperty<TransitionBase, AvaloniaProperty?> PropertyProperty =
AvaloniaProperty.RegisterDirect<TransitionBase, AvaloniaProperty?>(
nameof(Property),
o => o._prop,
(o, v) => o._prop = v);

private TimeSpan _duration;
private TimeSpan _delay = TimeSpan.Zero;
private Easing _easing = new LinearEasing();
private AvaloniaProperty? _prop;

/// <summary>
/// Gets or sets the duration of the transition.
/// </summary>
public TimeSpan Duration
{
get { return _duration; }
set { SetAndRaise(DurationProperty, ref _duration, value); }
}

/// <summary>
/// Gets or sets delay before starting the transition.
/// </summary>
public TimeSpan Delay
{
get { return _delay; }
set { SetAndRaise(DelayProperty, ref _delay, value); }
}

/// <summary>
/// Gets the easing class to be used.
/// </summary>
public Easing Easing
{
get { return _easing; }
set { SetAndRaise(EasingProperty, ref _easing, value); }
}

/// <inheritdocs/>
[DisallowNull]
public AvaloniaProperty? Property
{
get { return _prop; }
set { SetAndRaise(PropertyProperty, ref _prop, value); }
}

AvaloniaProperty ITransition.Property
{
get => Property ?? throw new InvalidOperationException("Transition has no property specified.");
set => Property = value;
}

/// <inheritdocs/>
IDisposable ITransition.Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
=> Apply(control, clock, oldValue, newValue);

internal abstract IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue);
}
}

0 comments on commit 0ecc683

Please sign in to comment.