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);