diff --git a/src/Avalonia.Animation/AnimationInstance`1.cs b/src/Avalonia.Animation/AnimationInstance`1.cs index 1ad609bce8..8184e68d42 100644 --- a/src/Avalonia.Animation/AnimationInstance`1.cs +++ b/src/Avalonia.Animation/AnimationInstance`1.cs @@ -72,10 +72,13 @@ namespace Avalonia.Animation _onCompleteAction = OnComplete; _interpolator = Interpolator; _baseClock = baseClock; - } + } protected override void Unsubscribed() { + //Animation may have been stopped before it has finished + ApplyFinalFill(); + _timerSubscription?.Dispose(); _clock.PlayState = PlayState.Stop; } @@ -98,11 +101,15 @@ namespace Avalonia.Animation } } - private void DoComplete() + private void ApplyFinalFill() { if (_fillMode == FillMode.Forward || _fillMode == FillMode.Both) _targetControl.SetValue(_parent.Property, _lastInterpValue, BindingPriority.LocalValue); + } + private void DoComplete() + { + ApplyFinalFill(); _onCompleteAction?.Invoke(); PublishCompleted(); } @@ -133,6 +140,7 @@ namespace Avalonia.Animation DoPlayStates(); var delayEndpoint = _delay; var iterationEndpoint = delayEndpoint + _duration; + var iterationTime = time; //determine if time is currently in the first iteration. if (time >= TimeSpan.Zero & time <= iterationEndpoint) @@ -142,7 +150,7 @@ namespace Avalonia.Animation else if (time > iterationEndpoint) { //Subtract first iteration to properly get the subsequent iteration time - time -= iterationEndpoint; + iterationTime -= iterationEndpoint; if (!_iterationDelay & delayEndpoint > TimeSpan.Zero) { @@ -151,39 +159,45 @@ namespace Avalonia.Animation } //Calculate the current iteration number - _currentIteration = (int)Math.Floor((double)((double)time.Ticks / iterationEndpoint.Ticks)) + 2; + _currentIteration = Math.Min(_repeatCount,(int)Math.Floor((double)((double)iterationTime.Ticks / iterationEndpoint.Ticks)) + 2); } else { return; } - time = TimeSpan.FromTicks((long)(time.Ticks % iterationEndpoint.Ticks)); - - if (!_isLooping) - { - if ((_currentIteration > _repeatCount) || (time > iterationEndpoint)) - DoComplete(); - } - - // Determine if the current iteration should have its normalized time inverted. + // Determine if the current iteration should have its normalized time inverted. bool isCurIterReverse = _animationDirection == PlaybackDirection.Normal ? false : _animationDirection == PlaybackDirection.Alternate ? (_currentIteration % 2 == 0) ? false : true : _animationDirection == PlaybackDirection.AlternateReverse ? (_currentIteration % 2 == 0) ? true : false : _animationDirection == PlaybackDirection.Reverse ? true : false; - - if (delayEndpoint > TimeSpan.Zero & time < delayEndpoint) + + if (!_isLooping) + { + var totalTime = _iterationDelay ? _repeatCount * ( _duration.Ticks + _delay.Ticks) : _repeatCount * _duration.Ticks + _delay.Ticks; + if (time.Ticks >= totalTime) + { + var easedTime = _easeFunc.Ease(isCurIterReverse ? 0.0 : 1.0); + _lastInterpValue = _interpolator(easedTime, _neutralValue); + + DoComplete(); + return; + } + } + iterationTime = TimeSpan.FromTicks((long)(iterationTime.Ticks % iterationEndpoint.Ticks)); + + if (delayEndpoint > TimeSpan.Zero & iterationTime < delayEndpoint) { DoDelay(); } else { // Offset the delay time - time -= delayEndpoint; + iterationTime -= delayEndpoint; iterationEndpoint -= delayEndpoint; // Normalize time - var interpVal = (double)time.Ticks / iterationEndpoint.Ticks; + var interpVal = (double)iterationTime.Ticks / iterationEndpoint.Ticks; if (isCurIterReverse) interpVal = 1 - interpVal; diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index d6c3a1041e..dc2884b36b 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -14,6 +14,7 @@ using Avalonia.Interactivity; using Avalonia.Media; using Avalonia.Metadata; using Avalonia.Data; +using Avalonia.Utilities; namespace Avalonia.Controls { @@ -655,6 +656,8 @@ namespace Avalonia.Controls if (_presenter != null && e.Device.Captured == _presenter) { var point = e.GetPosition(_presenter); + + point = new Point(MathUtilities.Clamp(point.X, 0, _presenter.Bounds.Width - 1), MathUtilities.Clamp(point.Y, 0, _presenter.Bounds.Height - 1)); CaretIndex = SelectionEnd = _presenter.GetCaretIndex(point); } } diff --git a/src/Avalonia.Native/.gitignore b/src/Avalonia.Native/.gitignore new file mode 100644 index 0000000000..b1153e777c --- /dev/null +++ b/src/Avalonia.Native/.gitignore @@ -0,0 +1 @@ +Generated/*.cs diff --git a/src/Avalonia.Native/Avalonia.Native.csproj b/src/Avalonia.Native/Avalonia.Native.csproj index 9d6a82a2fb..c8ee73ad5d 100644 --- a/src/Avalonia.Native/Avalonia.Native.csproj +++ b/src/Avalonia.Native/Avalonia.Native.csproj @@ -7,6 +7,8 @@ /usr/bin/castxml /usr/local/bin/castxml true + + $(MSBuildThisFileDirectory)/Generated diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index 2a8f517995..56c5c57f7b 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -121,7 +121,7 @@ namespace Avalonia.Skia int offset = 0; - if (point.X >= (rects[line.Start].X + line.Width) / 2 && line.Length > 0) + if (point.X >= (rects[line.Start].X + line.Width) && line.Length > 0) { offset = line.TextLength > line.Length ? line.Length : (line.Length - 1);