|
|
|
@ -5,9 +5,8 @@ namespace Avalonia.Animation.Keyframes |
|
|
|
/// <summary>
|
|
|
|
/// Provides statefulness for an iteration of a keyframe group animation.
|
|
|
|
/// </summary>
|
|
|
|
internal class KeyFramesStateMachine |
|
|
|
internal class KeyFramesStateMachine<T> : IObservable<object>, IDisposable |
|
|
|
{ |
|
|
|
|
|
|
|
ulong _delayTotalFrameCount, |
|
|
|
_durationTotalFrameCount, |
|
|
|
_delayFrameCount, |
|
|
|
@ -18,11 +17,11 @@ namespace Avalonia.Animation.Keyframes |
|
|
|
|
|
|
|
bool _isLooping, _isRepeating, _isReversed; |
|
|
|
private PlaybackDirection _animationDirection; |
|
|
|
KeyFramesStates _currentState; |
|
|
|
|
|
|
|
KeyFramesStates _currentState, _savedState; |
|
|
|
private Animation parentAnimation; |
|
|
|
internal bool _unsubscribe = false; |
|
|
|
private Animation _parentAnimation; |
|
|
|
private Animatable _targetAnimatable; |
|
|
|
double _outputTime = 0d; |
|
|
|
private IObserver<object> targetObserver; |
|
|
|
|
|
|
|
private enum KeyFramesStates |
|
|
|
{ |
|
|
|
@ -32,21 +31,14 @@ namespace Avalonia.Animation.Keyframes |
|
|
|
RUN_FORWARDS, |
|
|
|
RUN_BACKWARDS, |
|
|
|
RUN_COMPLETE, |
|
|
|
STOP |
|
|
|
PAUSE, |
|
|
|
STOP, |
|
|
|
DISPOSED |
|
|
|
} |
|
|
|
|
|
|
|
public void Start(Animation animation, Animatable control) |
|
|
|
public void Start(Animation animation) |
|
|
|
{ |
|
|
|
this._parentAnimation = animation; |
|
|
|
this._targetAnimatable = control; |
|
|
|
|
|
|
|
// int _delayFrameCount,
|
|
|
|
// _durationFrameCount,
|
|
|
|
// _repeatCount,
|
|
|
|
// _iterationDirection,
|
|
|
|
// _currentIteration,
|
|
|
|
// _totalIteration;
|
|
|
|
|
|
|
|
parentAnimation = animation; |
|
|
|
_delayTotalFrameCount = (ulong)(animation.Delay.Ticks / Timing.FrameTick.Ticks); |
|
|
|
_durationTotalFrameCount = (ulong)(animation.Duration.Ticks / Timing.FrameTick.Ticks); |
|
|
|
|
|
|
|
@ -78,37 +70,39 @@ namespace Avalonia.Animation.Keyframes |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
_animationDirection = animation.PlaybackDirection; |
|
|
|
|
|
|
|
switch (_animationDirection) |
|
|
|
|
|
|
|
switch (animation.PlaybackDirection) |
|
|
|
{ |
|
|
|
case PlaybackDirection.Reverse: |
|
|
|
case PlaybackDirection.AlternateReverse: |
|
|
|
SetInitialPlaybackDirection(true); |
|
|
|
_isReversed = true; |
|
|
|
break; |
|
|
|
default: |
|
|
|
SetInitialPlaybackDirection(false); |
|
|
|
_isReversed = false; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
_currentState = KeyFramesStates.DO_RUN; |
|
|
|
} |
|
|
|
|
|
|
|
private void SetInitialPlaybackDirection(bool isReversed) |
|
|
|
{ |
|
|
|
_isReversed = isReversed; |
|
|
|
} |
|
|
|
|
|
|
|
private bool GetPlaybackDirection() |
|
|
|
public double Step(PlayState _playState, Func<double, T> Interpolator) |
|
|
|
{ |
|
|
|
_isReversed = !_isReversed; |
|
|
|
return _isReversed; |
|
|
|
} |
|
|
|
if (_currentState == KeyFramesStates.DISPOSED) throw new InvalidProgramException("This KeyFrames Animation is already disposed."); |
|
|
|
|
|
|
|
public double Step(PlayState _playState) |
|
|
|
{ |
|
|
|
if (_playState == PlayState.Stop) _currentState = KeyFramesStates.STOP; |
|
|
|
|
|
|
|
// Save state and pause the machine
|
|
|
|
if (_playState == PlayState.Pause && _currentState != KeyFramesStates.PAUSE) |
|
|
|
{ |
|
|
|
_savedState = _currentState; |
|
|
|
_currentState = KeyFramesStates.PAUSE; |
|
|
|
} |
|
|
|
|
|
|
|
// Resume the previous state
|
|
|
|
if (_playState != PlayState.Pause && _currentState == KeyFramesStates.PAUSE) |
|
|
|
_currentState = _savedState; |
|
|
|
|
|
|
|
checkstate: |
|
|
|
switch (_currentState) |
|
|
|
{ |
|
|
|
case KeyFramesStates.DO_DELAY: |
|
|
|
@ -120,11 +114,22 @@ namespace Avalonia.Animation.Keyframes |
|
|
|
return 0d; |
|
|
|
|
|
|
|
case KeyFramesStates.DO_RUN: |
|
|
|
// temporary stuff.
|
|
|
|
_currentState = KeyFramesStates.RUN_FORWARDS; |
|
|
|
|
|
|
|
goto checkstate; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case KeyFramesStates.RUN_FORWARDS: |
|
|
|
// break;
|
|
|
|
// temporary stuff.
|
|
|
|
if (_durationFrameCount > _durationTotalFrameCount) |
|
|
|
_currentState = KeyFramesStates.RUN_COMPLETE; |
|
|
|
|
|
|
|
var tmp1 = (double)_durationFrameCount / _durationTotalFrameCount; |
|
|
|
var easedTime = parentAnimation.Easing.Ease(tmp1); |
|
|
|
_durationFrameCount++; |
|
|
|
targetObserver.OnNext(Interpolator(easedTime)); |
|
|
|
break; |
|
|
|
|
|
|
|
case KeyFramesStates.RUN_BACKWARDS: |
|
|
|
// break;
|
|
|
|
@ -133,11 +138,24 @@ namespace Avalonia.Animation.Keyframes |
|
|
|
// break;
|
|
|
|
|
|
|
|
case KeyFramesStates.STOP: |
|
|
|
targetObserver.OnCompleted(); |
|
|
|
_unsubscribe = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
public IDisposable Subscribe(IObserver<object> observer) |
|
|
|
{ |
|
|
|
this.targetObserver = observer; |
|
|
|
return this; |
|
|
|
} |
|
|
|
|
|
|
|
public void Dispose() |
|
|
|
{ |
|
|
|
_unsubscribe = true; |
|
|
|
_currentState = KeyFramesStates.DISPOSED; |
|
|
|
targetObserver = null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |