diff --git a/samples/RenderTest/MainWindow.xaml b/samples/RenderTest/MainWindow.xaml index f63dec230e..51da5f342a 100644 --- a/samples/RenderTest/MainWindow.xaml +++ b/samples/RenderTest/MainWindow.xaml @@ -1,6 +1,7 @@ + xmlns:pages="clr-namespace:RenderTest.Pages;assembly=RenderTest" MinWidth="400" MinHeight="200" + > diff --git a/samples/RenderTest/Pages/AnimationsPage.xaml b/samples/RenderTest/Pages/AnimationsPage.xaml index 6eb7067245..5cd4e6e431 100644 --- a/samples/RenderTest/Pages/AnimationsPage.xaml +++ b/samples/RenderTest/Pages/AnimationsPage.xaml @@ -1,2 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/RenderTest/Pages/AnimationsPage.xaml.cs b/samples/RenderTest/Pages/AnimationsPage.xaml.cs index d2e1750ba7..925ba9260c 100644 --- a/samples/RenderTest/Pages/AnimationsPage.xaml.cs +++ b/samples/RenderTest/Pages/AnimationsPage.xaml.cs @@ -15,7 +15,7 @@ namespace RenderTest.Pages public AnimationsPage() { this.InitializeComponent(); - this.CreateAnimations(); + // this.CreateAnimations(); } private void InitializeComponent() diff --git a/samples/RenderTest/RenderTest.csproj b/samples/RenderTest/RenderTest.csproj index b33d5d3c70..855445812a 100644 --- a/samples/RenderTest/RenderTest.csproj +++ b/samples/RenderTest/RenderTest.csproj @@ -1,18 +1,10 @@ - - - + - Debug - AnyCPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801} - WinExe - Properties + Exe + netcoreapp2.0 + false RenderTest RenderTest - v4.7 - 512 - true - AnyCPU @@ -33,152 +25,33 @@ prompt 4 - - - - - - - - - - - - - - - - App.xaml - - - DrawingPage.xaml - - - ClippingPage.xaml - - - AnimationsPage.xaml - - - - - MainWindow.xaml + + %(Filename) - - - - - - - - Designer - - - - - {d211e587-d8bc-45b9-95a4-f297c8fa5200} - Avalonia.Animation - - - {b09b78d8-9b26-48b0-9149-d64a2f120f3f} - Avalonia.Base - - - {d2221c82-4a25-4583-9b43-d791e3f6820c} - Avalonia.Controls - - - {799a7bb5-3c2c-48b6-85a7-406a12c420da} - Avalonia.DesignerSupport - - - {7062ae20-5dcc-4442-9645-8195bdece63e} - Avalonia.Diagnostics - - - {4a1abb09-9047-4bd5-a4ad-a055e52c5ee0} - Avalonia.DotNetFrameworkRuntime - - - {62024b2d-53eb-4638-b26b-85eeaa54866e} - Avalonia.Input - - - {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} - Avalonia.Interactivity - - - {42472427-4774-4c81-8aff-9f27b8e31721} - Avalonia.Layout - - - {b61b66a3-b82d-4875-8001-89d3394fe0c9} - Avalonia.Logging.Serilog - - - {6417b24e-49c2-4985-8db2-3ab9d898ec91} - Avalonia.ReactiveUI - - - {eb582467-6abb-43a1-b052-e981ba910e3a} - Avalonia.Visuals - - - {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} - Avalonia.Styling - - - {3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f} - Avalonia.Themes.Default - - - {3e53a01a-b331-47f3-b828-4a5717e77a24} - Avalonia.Markup.Xaml - - - {6417e941-21bc-467b-a771-0de389353ce6} - Avalonia.Markup - - - {7d2d3083-71dd-4cc9-8907-39a0d86fb322} - Avalonia.Skia - - - {3e908f67-5543-4879-a1dc-08eace79b3cd} - Avalonia.Direct2D1 - - - {811a76cf-1cf6-440f-963b-bbe31bd72a82} - Avalonia.Win32 - - - - - Designer - - - - - Designer - - - - - Designer - - - - + Designer - - Designer - + + + + + + + + + + + + + + + + + - diff --git a/samples/RenderTest/SideBar.xaml b/samples/RenderTest/SideBar.xaml index 7a0b515748..29e5d854f9 100644 --- a/samples/RenderTest/SideBar.xaml +++ b/samples/RenderTest/SideBar.xaml @@ -37,7 +37,7 @@ - + diff --git a/samples/RenderTest/ViewModels/MainWindowViewModel.cs b/samples/RenderTest/ViewModels/MainWindowViewModel.cs index b2fa2e8b7a..02a2abeb89 100644 --- a/samples/RenderTest/ViewModels/MainWindowViewModel.cs +++ b/samples/RenderTest/ViewModels/MainWindowViewModel.cs @@ -5,7 +5,7 @@ namespace RenderTest.ViewModels { public class MainWindowViewModel : ReactiveObject { - private bool drawDirtyRects = true; + private bool drawDirtyRects = false; private bool drawFps = true; public MainWindowViewModel() diff --git a/src/Avalonia.Animation/Animatable.cs b/src/Avalonia.Animation/Animatable.cs index 5b1f68a7a9..c4ee1d72e5 100644 --- a/src/Avalonia.Animation/Animatable.cs +++ b/src/Avalonia.Animation/Animatable.cs @@ -6,6 +6,7 @@ using Avalonia.Data; using System; using System.Reactive.Linq; using Avalonia.Collections; +using Avalonia.Animation.Transitions; namespace Avalonia.Animation { @@ -17,13 +18,13 @@ namespace Avalonia.Animation /// /// /// - public static readonly StyledProperty> TransitionsProperty = - AvaloniaProperty.Register>(nameof(Transitions)); + public static readonly StyledProperty TransitionsProperty = + AvaloniaProperty.Register(nameof(Transitions)); /// /// Gets or sets the property transitions for the control. /// - public AvaloniaList Transitions + public Transitions.Transitions Transitions { get { return GetValue(TransitionsProperty); } set { SetValue(TransitionsProperty, value); } diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Animation/Animation.cs index 41e4e2fee1..bd83020185 100644 --- a/src/Avalonia.Animation/Animation.cs +++ b/src/Avalonia.Animation/Animation.cs @@ -1,55 +1,72 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using Avalonia.Animation.Easings; +using Avalonia.Animation.Keyframes; +using Avalonia.Collections; +using Avalonia.Metadata; using System; +using System.Collections.Generic; namespace Avalonia.Animation { /// /// Tracks the progress of an animation. /// - public class Animation : IObservable, IDisposable + public class Animation : IDisposable, IAnimation { + private List_subscription = new List(); + /// - /// The animation being tracked. + /// Run time of this animation. /// - private readonly IObservable _inner; + public TimeSpan Duration { get; set; } /// - /// The disposable used to cancel the animation. + /// Delay time for animation. /// - private readonly IDisposable _subscription; + public TimeSpan Delay { get; set; } + + /// + /// Easing function to be used. + /// + public Easing Easing { get; set; } = new LinearEasing(); /// - /// Initializes a new instance of the class. + /// A list of objects. /// - /// The animation observable being tracked. - /// A disposable used to cancel the animation. - public Animation(IObservable inner, IDisposable subscription) - { - _inner = inner; - _subscription = subscription; - } + [Content] + public AvaloniaList Children { get; set; } = new AvaloniaList(); /// /// Cancels the animation. /// public void Dispose() { - _subscription.Dispose(); + foreach(var sub in _subscription) sub.Dispose(); } - /// - /// Notifies the provider that an observer is to receive notifications. - /// - /// The observer. - /// - /// A reference to an interface that allows observers to stop receiving notifications - /// before the provider has finished sending them. - /// - public IDisposable Subscribe(IObserver observer) + /// + public IDisposable Apply(Animatable control, IObservable matchObs) { - return _inner.Subscribe(observer); + foreach (IKeyFrames keyframes in Children) + { + _subscription.Add(keyframes.Apply(this, control, matchObs)); + } + return this; } + + ///// + ///// Notifies the provider that an observer is to receive notifications. + ///// + ///// The observer. + ///// + ///// A reference to an interface that allows observers to stop receiving notifications + ///// before the provider has finished sending them. + ///// + //public IDisposable Subscribe(IObserver observer) + //{ + // return _inner.Subscribe(observer); + //} } } diff --git a/src/Avalonia.Animation/Easing.cs b/src/Avalonia.Animation/Easing.cs index 75b98e8a3a..97c10f37ea 100644 --- a/src/Avalonia.Animation/Easing.cs +++ b/src/Avalonia.Animation/Easing.cs @@ -6,7 +6,7 @@ using System.Reflection; using System.Linq; using System.ComponentModel; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Base class for all Easing classes. diff --git a/src/Avalonia.Animation/Easing/BackEaseIn.cs b/src/Avalonia.Animation/Easing/BackEaseIn.cs index c846d6116d..4ea17a353a 100644 --- a/src/Avalonia.Animation/Easing/BackEaseIn.cs +++ b/src/Avalonia.Animation/Easing/BackEaseIn.cs @@ -3,7 +3,7 @@ using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases in a value diff --git a/src/Avalonia.Animation/Easing/BackEaseOut.cs b/src/Avalonia.Animation/Easing/BackEaseOut.cs index f671d61040..ed5628dd0b 100644 --- a/src/Avalonia.Animation/Easing/BackEaseOut.cs +++ b/src/Avalonia.Animation/Easing/BackEaseOut.cs @@ -3,7 +3,7 @@ using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases out a value diff --git a/src/Avalonia.Animation/Easing/BounceEaseIn.cs b/src/Avalonia.Animation/Easing/BounceEaseIn.cs index 5cf34e3f9a..6ed6f3fe82 100644 --- a/src/Avalonia.Animation/Easing/BounceEaseIn.cs +++ b/src/Avalonia.Animation/Easing/BounceEaseIn.cs @@ -2,7 +2,9 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +using Avalonia.Animation.Utils; + +namespace Avalonia.Animation.Easings { /// /// Eases in a value @@ -13,7 +15,7 @@ namespace Avalonia.Animation /// public override double Ease(double progress) { - return 1 - BounceEaseHelper.Bounce(1 - progress); + return 1 - BounceEaseUtils.Bounce(1 - progress); } } diff --git a/src/Avalonia.Animation/Easing/BounceEaseInOut.cs b/src/Avalonia.Animation/Easing/BounceEaseInOut.cs index 6db0424658..ed32b3df9d 100644 --- a/src/Avalonia.Animation/Easing/BounceEaseInOut.cs +++ b/src/Avalonia.Animation/Easing/BounceEaseInOut.cs @@ -1,7 +1,9 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +using Avalonia.Animation.Utils; + +namespace Avalonia.Animation.Easings { /// /// Eases a value @@ -15,11 +17,11 @@ namespace Avalonia.Animation double p = progress; if (p < 0.5d) { - return 0.5f * (1 - BounceEaseHelper.Bounce(1 - (p * 2))); + return 0.5f * (1 - BounceEaseUtils.Bounce(1 - (p * 2))); } else { - return 0.5f * BounceEaseHelper.Bounce(p * 2 - 1) + 0.5f; + return 0.5f * BounceEaseUtils.Bounce(p * 2 - 1) + 0.5f; } } diff --git a/src/Avalonia.Animation/Easing/BounceEaseOut.cs b/src/Avalonia.Animation/Easing/BounceEaseOut.cs index 9cb4e9633d..555c8d9c79 100644 --- a/src/Avalonia.Animation/Easing/BounceEaseOut.cs +++ b/src/Avalonia.Animation/Easing/BounceEaseOut.cs @@ -1,8 +1,8 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using Avalonia.Animation.Utils; - -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases out a value @@ -13,7 +13,7 @@ namespace Avalonia.Animation /// public override double Ease(double progress) { - return BounceEaseHelper.Bounce(progress); + return BounceEaseUtils.Bounce(progress); } } } diff --git a/src/Avalonia.Animation/Easing/CircularEaseIn.cs b/src/Avalonia.Animation/Easing/CircularEaseIn.cs index 21b77db582..78b61226f7 100644 --- a/src/Avalonia.Animation/Easing/CircularEaseIn.cs +++ b/src/Avalonia.Animation/Easing/CircularEaseIn.cs @@ -3,7 +3,7 @@ using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases in a value diff --git a/src/Avalonia.Animation/Easing/CircularEaseInOut.cs b/src/Avalonia.Animation/Easing/CircularEaseInOut.cs index a5198a019f..61c1df9242 100644 --- a/src/Avalonia.Animation/Easing/CircularEaseInOut.cs +++ b/src/Avalonia.Animation/Easing/CircularEaseInOut.cs @@ -3,7 +3,7 @@ using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases a value diff --git a/src/Avalonia.Animation/Easing/CircularEaseOut.cs b/src/Avalonia.Animation/Easing/CircularEaseOut.cs index 33391ed816..2aa6161783 100644 --- a/src/Avalonia.Animation/Easing/CircularEaseOut.cs +++ b/src/Avalonia.Animation/Easing/CircularEaseOut.cs @@ -3,7 +3,7 @@ using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases out a value diff --git a/src/Avalonia.Animation/Easing/CubicEaseIn.cs b/src/Avalonia.Animation/Easing/CubicEaseIn.cs index 653164d7ab..1997493fc0 100644 --- a/src/Avalonia.Animation/Easing/CubicEaseIn.cs +++ b/src/Avalonia.Animation/Easing/CubicEaseIn.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases in a value diff --git a/src/Avalonia.Animation/Easing/CubicEaseInOut.cs b/src/Avalonia.Animation/Easing/CubicEaseInOut.cs index ffdce75d45..a3d788701c 100644 --- a/src/Avalonia.Animation/Easing/CubicEaseInOut.cs +++ b/src/Avalonia.Animation/Easing/CubicEaseInOut.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases a value diff --git a/src/Avalonia.Animation/Easing/CubicEaseOut.cs b/src/Avalonia.Animation/Easing/CubicEaseOut.cs index 6bbe756477..cfa42afeb9 100644 --- a/src/Avalonia.Animation/Easing/CubicEaseOut.cs +++ b/src/Avalonia.Animation/Easing/CubicEaseOut.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases out a value diff --git a/src/Avalonia.Animation/Easing/ElasticEaseIn.cs b/src/Avalonia.Animation/Easing/ElasticEaseIn.cs index b0a95d8dc0..3a44eca8da 100644 --- a/src/Avalonia.Animation/Easing/ElasticEaseIn.cs +++ b/src/Avalonia.Animation/Easing/ElasticEaseIn.cs @@ -1,9 +1,10 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using Avalonia.Animation.Utils; using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases in a value @@ -15,7 +16,7 @@ namespace Avalonia.Animation public override double Ease(double progress) { double p = progress; - return Math.Sin(13d * EasingConstants.HALFPI * p) * Math.Pow(2d, 10d * (p - 1)); + return Math.Sin(13d * EasingUtils.HALFPI * p) * Math.Pow(2d, 10d * (p - 1)); } } diff --git a/src/Avalonia.Animation/Easing/ElasticEaseInOut.cs b/src/Avalonia.Animation/Easing/ElasticEaseInOut.cs index 85dcfbd618..6e443dc720 100644 --- a/src/Avalonia.Animation/Easing/ElasticEaseInOut.cs +++ b/src/Avalonia.Animation/Easing/ElasticEaseInOut.cs @@ -2,8 +2,9 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using Avalonia.Animation.Utils; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases a value @@ -18,11 +19,11 @@ namespace Avalonia.Animation if (p < 0.5d) { - return 0.5d * Math.Sin(13d * EasingConstants.HALFPI * (2d * p)) * Math.Pow(2d, 10d * ((2d * p) - 1d)); + return 0.5d * Math.Sin(13d * EasingUtils.HALFPI * (2d * p)) * Math.Pow(2d, 10d * ((2d * p) - 1d)); } else { - return 0.5d * (Math.Sin(-13d * EasingConstants.HALFPI * ((2d * p - 1d) + 1d)) * Math.Pow(2d, -10d * (2d * p - 1d)) + 2d); + return 0.5d * (Math.Sin(-13d * EasingUtils.HALFPI * ((2d * p - 1d) + 1d)) * Math.Pow(2d, -10d * (2d * p - 1d)) + 2d); } } diff --git a/src/Avalonia.Animation/Easing/ElasticEaseOut.cs b/src/Avalonia.Animation/Easing/ElasticEaseOut.cs index 830198468d..fd8380ff39 100644 --- a/src/Avalonia.Animation/Easing/ElasticEaseOut.cs +++ b/src/Avalonia.Animation/Easing/ElasticEaseOut.cs @@ -1,9 +1,10 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using Avalonia.Animation.Utils; using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases out a value @@ -15,7 +16,7 @@ namespace Avalonia.Animation public override double Ease(double progress) { double p = progress; - return Math.Sin(-13d * EasingConstants.HALFPI * (p + 1)) * Math.Pow(2d, -10d * p) + 1d; + return Math.Sin(-13d * EasingUtils.HALFPI * (p + 1)) * Math.Pow(2d, -10d * p) + 1d; } diff --git a/src/Avalonia.Animation/Easing/ExponentialEaseIn.cs b/src/Avalonia.Animation/Easing/ExponentialEaseIn.cs index 5b9154d29c..14977f6783 100644 --- a/src/Avalonia.Animation/Easing/ExponentialEaseIn.cs +++ b/src/Avalonia.Animation/Easing/ExponentialEaseIn.cs @@ -3,7 +3,7 @@ using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases in a value diff --git a/src/Avalonia.Animation/Easing/ExponentialEaseInOut.cs b/src/Avalonia.Animation/Easing/ExponentialEaseInOut.cs index 0eaef18464..a3ce11e3b9 100644 --- a/src/Avalonia.Animation/Easing/ExponentialEaseInOut.cs +++ b/src/Avalonia.Animation/Easing/ExponentialEaseInOut.cs @@ -3,7 +3,7 @@ using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases a value diff --git a/src/Avalonia.Animation/Easing/ExponentialEaseOut.cs b/src/Avalonia.Animation/Easing/ExponentialEaseOut.cs index c071d18d2e..b89f8e9fa2 100644 --- a/src/Avalonia.Animation/Easing/ExponentialEaseOut.cs +++ b/src/Avalonia.Animation/Easing/ExponentialEaseOut.cs @@ -3,7 +3,7 @@ using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases out a value diff --git a/src/Avalonia.Animation/Easing/LinearEasing.cs b/src/Avalonia.Animation/Easing/LinearEasing.cs index fcbf6053f4..99278cb1f7 100644 --- a/src/Avalonia.Animation/Easing/LinearEasing.cs +++ b/src/Avalonia.Animation/Easing/LinearEasing.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Linearly eases a value. diff --git a/src/Avalonia.Animation/Easing/QuadraticEaseIn.cs b/src/Avalonia.Animation/Easing/QuadraticEaseIn.cs index 641fba4892..6c29b31516 100644 --- a/src/Avalonia.Animation/Easing/QuadraticEaseIn.cs +++ b/src/Avalonia.Animation/Easing/QuadraticEaseIn.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases in a value diff --git a/src/Avalonia.Animation/Easing/QuadraticEaseInOut.cs b/src/Avalonia.Animation/Easing/QuadraticEaseInOut.cs index 384c3caf32..55c7e35cef 100644 --- a/src/Avalonia.Animation/Easing/QuadraticEaseInOut.cs +++ b/src/Avalonia.Animation/Easing/QuadraticEaseInOut.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases a value diff --git a/src/Avalonia.Animation/Easing/QuadraticEaseOut.cs b/src/Avalonia.Animation/Easing/QuadraticEaseOut.cs index 14fd877ad4..58092677f0 100644 --- a/src/Avalonia.Animation/Easing/QuadraticEaseOut.cs +++ b/src/Avalonia.Animation/Easing/QuadraticEaseOut.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases out a value diff --git a/src/Avalonia.Animation/Easing/QuarticEaseIn.cs b/src/Avalonia.Animation/Easing/QuarticEaseIn.cs index a5efa241be..fee78761ce 100644 --- a/src/Avalonia.Animation/Easing/QuarticEaseIn.cs +++ b/src/Avalonia.Animation/Easing/QuarticEaseIn.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases in a value diff --git a/src/Avalonia.Animation/Easing/QuarticEaseInOut.cs b/src/Avalonia.Animation/Easing/QuarticEaseInOut.cs index d5cd2622cb..227f0a89e7 100644 --- a/src/Avalonia.Animation/Easing/QuarticEaseInOut.cs +++ b/src/Avalonia.Animation/Easing/QuarticEaseInOut.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases a value diff --git a/src/Avalonia.Animation/Easing/QuarticEaseOut.cs b/src/Avalonia.Animation/Easing/QuarticEaseOut.cs index 5ecb3a7a0b..2a1e2ea92b 100644 --- a/src/Avalonia.Animation/Easing/QuarticEaseOut.cs +++ b/src/Avalonia.Animation/Easing/QuarticEaseOut.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases out a value diff --git a/src/Avalonia.Animation/Easing/QuinticEaseIn.cs b/src/Avalonia.Animation/Easing/QuinticEaseIn.cs index 8dc6ad6bc8..79cb607fd4 100644 --- a/src/Avalonia.Animation/Easing/QuinticEaseIn.cs +++ b/src/Avalonia.Animation/Easing/QuinticEaseIn.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases in a value diff --git a/src/Avalonia.Animation/Easing/QuinticEaseInOut.cs b/src/Avalonia.Animation/Easing/QuinticEaseInOut.cs index 87f3c38dad..d51f7cfefe 100644 --- a/src/Avalonia.Animation/Easing/QuinticEaseInOut.cs +++ b/src/Avalonia.Animation/Easing/QuinticEaseInOut.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases a value diff --git a/src/Avalonia.Animation/Easing/QuinticEaseOut.cs b/src/Avalonia.Animation/Easing/QuinticEaseOut.cs index f4054c8da2..63d45f3290 100644 --- a/src/Avalonia.Animation/Easing/QuinticEaseOut.cs +++ b/src/Avalonia.Animation/Easing/QuinticEaseOut.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases out a value diff --git a/src/Avalonia.Animation/Easing/SineEaseIn.cs b/src/Avalonia.Animation/Easing/SineEaseIn.cs index 49c633ec5c..31a8f0ca94 100644 --- a/src/Avalonia.Animation/Easing/SineEaseIn.cs +++ b/src/Avalonia.Animation/Easing/SineEaseIn.cs @@ -1,9 +1,10 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using Avalonia.Animation.Utils; using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases in a value @@ -14,7 +15,7 @@ namespace Avalonia.Animation /// public override double Ease(double progress) { - return Math.Sin((progress - 1) * EasingConstants.HALFPI) + 1; + return Math.Sin((progress - 1) * EasingUtils.HALFPI) + 1; } } } diff --git a/src/Avalonia.Animation/Easing/SineEaseInOut.cs b/src/Avalonia.Animation/Easing/SineEaseInOut.cs index 94b528c728..51052575e2 100644 --- a/src/Avalonia.Animation/Easing/SineEaseInOut.cs +++ b/src/Avalonia.Animation/Easing/SineEaseInOut.cs @@ -3,7 +3,7 @@ using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases a value diff --git a/src/Avalonia.Animation/Easing/SineEaseOut.cs b/src/Avalonia.Animation/Easing/SineEaseOut.cs index 7d0658c389..ed5a998e30 100644 --- a/src/Avalonia.Animation/Easing/SineEaseOut.cs +++ b/src/Avalonia.Animation/Easing/SineEaseOut.cs @@ -1,9 +1,10 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using Avalonia.Animation.Utils; using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Eases out a value @@ -15,7 +16,7 @@ namespace Avalonia.Animation /// public override double Ease(double progress) { - return Math.Sin(progress * EasingConstants.HALFPI); + return Math.Sin(progress * EasingUtils.HALFPI); } } } diff --git a/src/Avalonia.Animation/IAnimation.cs b/src/Avalonia.Animation/IAnimation.cs new file mode 100644 index 0000000000..4de7e46af5 --- /dev/null +++ b/src/Avalonia.Animation/IAnimation.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Avalonia.Animation +{ + /// + /// Interface for Animation objects + /// + public interface IAnimation + { + /// + /// Apply the animation to the specified control + /// + IDisposable Apply(Animatable control, IObservable match); + } +} diff --git a/src/Avalonia.Animation/IEasing.cs b/src/Avalonia.Animation/IEasing.cs index fc1f2efc18..3c954a8cab 100644 --- a/src/Avalonia.Animation/IEasing.cs +++ b/src/Avalonia.Animation/IEasing.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Easings { /// /// Defines the interface for easing classes. diff --git a/src/Avalonia.Animation/Keyframes/Cue.cs b/src/Avalonia.Animation/Keyframes/Cue.cs new file mode 100644 index 0000000000..3f120ef604 --- /dev/null +++ b/src/Avalonia.Animation/Keyframes/Cue.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Text; + +namespace Avalonia.Animation.Keyframes +{ + /// + /// A Cue object for . + /// + [TypeConverter(typeof(CueTypeConverter))] + public struct Cue : IEquatable, IEquatable + { + /// + /// The normalized percent value, ranging from 0.0 to 1.0 + /// + public double CueValue { get; } + + /// + /// Sets a new object. + /// + /// + public Cue(double value) + { + if (value <= 1 && value >= 0) + CueValue = value; + else + throw new ArgumentException($"This cue object's value should be within or equal to 0.0 and 1.0"); + } + + /// + /// Parses a string to a object. + /// + public static object Parse(string value, CultureInfo culture) + { + string v = value; + + if (value.EndsWith("%")) + { + v = v.TrimEnd('%'); + } + + if (double.TryParse(v, NumberStyles.Float, culture, out double res)) + { + return new Cue(res / 100d); + } + else + { + throw new FormatException($"Invalid Cue string \"{value}\""); + } + } + + /// + /// Checks for equality between two s. + /// + /// The second cue. + public bool Equals(Cue other) + { + return CueValue == other.CueValue; + } + + /// + /// Checks for equality between a + /// and a value. + /// + /// + /// + public bool Equals(double other) + { + return CueValue == other; + } + } + + public class CueTypeConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + return Cue.Parse((string)value, culture); + } + } + +} diff --git a/src/Avalonia.Animation/Keyframes/DoubleKeyFrames.cs b/src/Avalonia.Animation/Keyframes/DoubleKeyFrames.cs new file mode 100644 index 0000000000..00558430e0 --- /dev/null +++ b/src/Avalonia.Animation/Keyframes/DoubleKeyFrames.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using System.Reactive.Linq; +using System.Diagnostics; +using Avalonia.Animation.Utils; +using Avalonia.Data; + +namespace Avalonia.Animation.Keyframes +{ + /// + /// Key frames that handles properties. + /// + public class DoubleKeyFrames : KeyFrames + { + /// + public override IDisposable DoInterpolation(Animation animation, Animatable control, Dictionary sortedkeyValues) + { + var timer = Timing.GetTimer(animation.Duration, animation.Delay); + + + var interp = timer.Select(p => + { + // Handle the errors rather naively, for now. + try + { + var x = animation.Easing.Ease(p); + + // Get a pair of keyframes to make the interpolation. + KeyValuePair firstCue, lastCue; + + firstCue = sortedkeyValues.First(); + lastCue = sortedkeyValues.Last(); + + // This should be changed later for a much more efficient one + if (sortedkeyValues.Count() > 2) + { + bool isWithinRange_Start = DoubleUtils.AboutEqual(x, 0.0) || x > 0.0; + bool isWithinRange_End = DoubleUtils.AboutEqual(x, 1.0) || x < 1.0; + + if (isWithinRange_Start && isWithinRange_End) + { + + firstCue = sortedkeyValues.Where(j => j.Key <= x).Last(); + lastCue = sortedkeyValues.Where(j=> j.Key >= firstCue.Key).First(); + } + else if (!isWithinRange_Start) + { + firstCue = sortedkeyValues.First(); + lastCue = sortedkeyValues.Skip(1).First(); + } + else if (!isWithinRange_End) + { + firstCue = sortedkeyValues.Skip(sortedkeyValues.Count() - 1).First(); + lastCue = sortedkeyValues.Last(); + } + else + { + throw new InvalidOperationException + ($"Can't find KeyFrames within the specified Easing time {x}"); + } + } + + // Piecewise Linear interpolation, courtesy of wikipedia + var y0 = firstCue.Value; + var x0 = firstCue.Key; + var y1 = lastCue.Value; + var x1 = lastCue.Key; + var y = ((y0 * (x1 - x)) + (y1 * (x - x0))) / x1 - x0; + + return y; + } + catch (Exception e) + { + Debug.WriteLine(e); + return 1; + } + }); + + + return control.Bind(Property, interp.Select(p => (object)p), BindingPriority.Animation); + } + + + } +} diff --git a/src/Avalonia.Animation/Keyframes/IKeyFrames.cs b/src/Avalonia.Animation/Keyframes/IKeyFrames.cs new file mode 100644 index 0000000000..6c49063615 --- /dev/null +++ b/src/Avalonia.Animation/Keyframes/IKeyFrames.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Avalonia.Animation.Keyframes +{ + /// + /// Interface for Keyframe group object + /// + public interface IKeyFrames + { + /// + /// Applies the current KeyFrame group to the specified control. + /// + IDisposable Apply(Animation animation, Animatable control, IObservable obsMatch); + } +} diff --git a/src/Avalonia.Animation/Keyframes/KeyFrame.cs b/src/Avalonia.Animation/Keyframes/KeyFrame.cs new file mode 100644 index 0000000000..982997c5e3 --- /dev/null +++ b/src/Avalonia.Animation/Keyframes/KeyFrame.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; + +namespace Avalonia.Animation.Keyframes +{ + + /// + /// Stores data regarding a specific key + /// point and value in an animation. + /// + public class KeyFrame + { + internal bool timeSpanSet, cueSet; + + private TimeSpan _ktimeSpan; + private Cue _kCue; + + /// + /// Gets or sets the key time of this . + /// + /// The key time. + public TimeSpan KeyTime + { + get + { + + return _ktimeSpan; + } + set + { + if (cueSet) + { + throw new InvalidOperationException($"You can only set either {nameof(KeyTime)} or {nameof(Cue)}."); + } + timeSpanSet = true; + _ktimeSpan = value; + } + } + + /// + /// Gets or sets the cue of this . + /// + /// The cue. + public Cue Cue + { + get + { + + return _kCue; + } + set + { + if (timeSpanSet) + { + throw new InvalidOperationException($"You can only set either {nameof(KeyTime)} or {nameof(Cue)}."); + } + cueSet = true; + _kCue = value; + } + } + + + public object Value { get; set; } + + + ///// + ///// Initializes a new instance of the class. + ///// + //public KeyFrame() + //{ + + //} + + } + + + +} diff --git a/src/Avalonia.Animation/Keyframes/KeyFrames.cs b/src/Avalonia.Animation/Keyframes/KeyFrames.cs new file mode 100644 index 0000000000..923e6fcbc5 --- /dev/null +++ b/src/Avalonia.Animation/Keyframes/KeyFrames.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Avalonia.Collections; +using System.ComponentModel; +using Avalonia.Animation.Utils; +using System.Reactive.Linq; +using System.Linq; + +namespace Avalonia.Animation.Keyframes +{ + /// + /// Base class for KeyFrames + /// + public abstract class KeyFrames : AvaloniaList, IKeyFrames + { + + /// + /// Target property. + /// + public AvaloniaProperty Property { get; set; } + + /// Enable if the derived class will do the verification of + /// its keyframes. + internal bool IsVerfifiedAndConverted; + + /// + public virtual IDisposable Apply(Animation animation, Animatable control, IObservable obsMatch) + { + if(obsMatch == null) return null; + + if (!IsVerfifiedAndConverted) + VerifyKeyFrames(animation, typeof(T)); + + return obsMatch + .Where(p => p == true) + .Subscribe(_ => DoInterpolation(animation, control, ConvertedValues)); + } + + + /// + /// Interpolates the given keyframes to the control. + /// + public abstract IDisposable DoInterpolation(Animation animation, + Animatable control, + Dictionary keyValues); + + internal Dictionary ConvertedValues = new Dictionary(); + + /// + /// Verifies keyframe value types. + /// + private void VerifyKeyFrames(Animation animation, Type type) + { + var typeConv = TypeDescriptor.GetConverter(type); + + foreach (KeyFrame k in this) + { + if (k.Value == null) + { + throw new ArgumentNullException($"KeyFrame value can't be null."); + } + if (!typeConv.CanConvertTo(k.Value.GetType())) + { + throw new InvalidCastException($"KeyFrame value doesnt match property type."); + } + + T convertedValue = (T)typeConv.ConvertTo(k.Value, type); + + Cue _normalizedCue = k.Cue; + + if (k.timeSpanSet) + { + _normalizedCue = new Cue(k.KeyTime.Ticks / animation.Duration.Ticks); + } + + ConvertedValues.Add(_normalizedCue.CueValue, convertedValue); + + } + + // This can be optional if we ever try to make + // the default start and end values to be the + // property's prior value. + SortKeyFrameCues(ConvertedValues); + + IsVerfifiedAndConverted = true; + + } + + private void SortKeyFrameCues(Dictionary convertedValues) + { + SortKeyFrameCues(convertedValues.ToDictionary((k) => k.Key, (v) => (object)v.Value)); + } + + internal void SortKeyFrameCues(Dictionary convertedValues) + { + bool hasStartKey, hasEndKey; + hasStartKey = hasEndKey = false; + + foreach (var converted in ConvertedValues.Keys) + { + if (DoubleUtils.AboutEqual(converted, 0.0)) + { + hasStartKey = true; + } + else if (DoubleUtils.AboutEqual(converted, 1.0)) + { + hasEndKey = true; + } + } + + if (!hasStartKey && !hasEndKey) + throw new InvalidOperationException + ($"{this.GetType().Name} must have a starting (0% cue) and ending (100% cue) keyframe."); + + // Sort Cues, in case they don't order it by themselves. + ConvertedValues = ConvertedValues.OrderBy(p => p.Key) + .ToDictionary((k) => k.Key, (v) => v.Value); + + } + } +} diff --git a/src/Avalonia.Animation/Properties/AssemblyInfo.cs b/src/Avalonia.Animation/Properties/AssemblyInfo.cs index 7e4f2b340f..8234e75386 100644 --- a/src/Avalonia.Animation/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Animation/Properties/AssemblyInfo.cs @@ -3,6 +3,11 @@ using Avalonia.Metadata; using System.Reflection; +using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Avalonia.Animation")] -[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation")] \ No newline at end of file +[assembly: InternalsVisibleTo("Avalonia.Visuals")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Keyframes")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Transitions")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Easings")] \ No newline at end of file diff --git a/src/Avalonia.Animation/Timing.cs b/src/Avalonia.Animation/Timing.cs index a22dc1a6a7..d8ccafac62 100644 --- a/src/Avalonia.Animation/Timing.cs +++ b/src/Avalonia.Animation/Timing.cs @@ -88,6 +88,27 @@ namespace Avalonia.Animation .Concat(Observable.Return(1.0)); } + /// + /// Gets a timer that fires every frame for the specified duration with delay. + /// + /// + /// An observable that notifies the subscriber of the progress along the animation. + /// + /// + /// The parameter passed to the subscriber is the progress along the animation, with + /// 0 being the start and 1 being the end. The observable is guaranteed to fire 0 + /// immediately on subscribe and 1 at the end of the duration. + /// + public static IObservable GetTimer(TimeSpan duration, TimeSpan delay) + { + var startTime = Stopwatch.Elapsed.Ticks + delay.Ticks; + var endTime = startTime + duration.Ticks; + return Timer + .TakeWhile(x => x.Ticks < endTime) + .Select(x => (x.Ticks - startTime) / (double)duration.Ticks) + .StartWith(0.0) + .Concat(Observable.Return(1.0)); + } } } diff --git a/src/Avalonia.Animation/Transitions/DoubleTransition.cs b/src/Avalonia.Animation/Transitions/DoubleTransition.cs index 26f7f975e8..4af23b3219 100644 --- a/src/Avalonia.Animation/Transitions/DoubleTransition.cs +++ b/src/Avalonia.Animation/Transitions/DoubleTransition.cs @@ -5,7 +5,7 @@ using Avalonia.Metadata; using System; using System.Reactive.Linq; -namespace Avalonia.Animation +namespace Avalonia.Animation.Transitions { /// /// Transition class that handles with types. diff --git a/src/Avalonia.Animation/Transitions/FloatTransition.cs b/src/Avalonia.Animation/Transitions/FloatTransition.cs index b94295d311..c0664295a5 100644 --- a/src/Avalonia.Animation/Transitions/FloatTransition.cs +++ b/src/Avalonia.Animation/Transitions/FloatTransition.cs @@ -5,7 +5,7 @@ using Avalonia.Metadata; using System; using System.Reactive.Linq; -namespace Avalonia.Animation +namespace Avalonia.Animation.Transitions { /// /// Transition class that handles with types. diff --git a/src/Avalonia.Animation/ITransition.cs b/src/Avalonia.Animation/Transitions/ITransition.cs similarity index 89% rename from src/Avalonia.Animation/ITransition.cs rename to src/Avalonia.Animation/Transitions/ITransition.cs index f5dd91739a..b34ad2d4fe 100644 --- a/src/Avalonia.Animation/ITransition.cs +++ b/src/Avalonia.Animation/Transitions/ITransition.cs @@ -5,10 +5,10 @@ using Avalonia.Metadata; using System; using System.Reactive.Linq; -namespace Avalonia.Animation +namespace Avalonia.Animation.Transitions { /// - /// Interface for Property Transition objects. + /// Interface for Transition objects. /// public interface ITransition { diff --git a/src/Avalonia.Animation/Transitions/IntegerTransition.cs b/src/Avalonia.Animation/Transitions/IntegerTransition.cs index 200b93a3df..cbef37972a 100644 --- a/src/Avalonia.Animation/Transitions/IntegerTransition.cs +++ b/src/Avalonia.Animation/Transitions/IntegerTransition.cs @@ -5,7 +5,7 @@ using Avalonia.Metadata; using System; using System.Reactive.Linq; -namespace Avalonia.Animation +namespace Avalonia.Animation.Transitions { /// /// Transition class that handles with types. diff --git a/src/Avalonia.Animation/Transition.cs b/src/Avalonia.Animation/Transitions/Transition.cs similarity index 93% rename from src/Avalonia.Animation/Transition.cs rename to src/Avalonia.Animation/Transitions/Transition.cs index 808e7f69de..a93b129e75 100644 --- a/src/Avalonia.Animation/Transition.cs +++ b/src/Avalonia.Animation/Transitions/Transition.cs @@ -4,8 +4,9 @@ using Avalonia.Metadata; using System; using System.Reactive.Linq; +using Avalonia.Animation.Easings; -namespace Avalonia.Animation +namespace Avalonia.Animation.Transitions { /// /// Defines how a property should be animated using a transition. @@ -13,7 +14,7 @@ namespace Avalonia.Animation public abstract class Transition : ITransition { private AvaloniaProperty _prop; - private IEasing _easing; + private Easing _easing; /// /// Gets the duration of the animation. @@ -23,7 +24,7 @@ namespace Avalonia.Animation /// /// Gets the easing class to be used. /// - public IEasing Easing + public Easing Easing { get { diff --git a/src/Avalonia.Animation/Transitions.cs b/src/Avalonia.Animation/Transitions/Transitions.cs similarity index 93% rename from src/Avalonia.Animation/Transitions.cs rename to src/Avalonia.Animation/Transitions/Transitions.cs index 7e742fc0b4..14e5b4e6fd 100644 --- a/src/Avalonia.Animation/Transitions.cs +++ b/src/Avalonia.Animation/Transitions/Transitions.cs @@ -3,7 +3,7 @@ using Avalonia.Collections; -namespace Avalonia.Animation +namespace Avalonia.Animation.Transitions { /// /// A collection of definitions. diff --git a/src/Avalonia.Animation/Helpers/BounceEaseHelper.cs b/src/Avalonia.Animation/Utils/BounceEaseUtils.cs similarity index 94% rename from src/Avalonia.Animation/Helpers/BounceEaseHelper.cs rename to src/Avalonia.Animation/Utils/BounceEaseUtils.cs index b0da648fd3..cfb9c432ae 100644 --- a/src/Avalonia.Animation/Helpers/BounceEaseHelper.cs +++ b/src/Avalonia.Animation/Utils/BounceEaseUtils.cs @@ -1,12 +1,12 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -namespace Avalonia.Animation +namespace Avalonia.Animation.Utils { /// /// Helper static class for BounceEase classes. /// - internal static class BounceEaseHelper + internal static class BounceEaseUtils { /// /// Returns the consequent value of diff --git a/src/Avalonia.Animation/Helpers/DoubleHelper.cs b/src/Avalonia.Animation/Utils/DoubleUtils.cs similarity index 86% rename from src/Avalonia.Animation/Helpers/DoubleHelper.cs rename to src/Avalonia.Animation/Utils/DoubleUtils.cs index bc95a2bb14..67943b687d 100644 --- a/src/Avalonia.Animation/Helpers/DoubleHelper.cs +++ b/src/Avalonia.Animation/Utils/DoubleUtils.cs @@ -5,9 +5,9 @@ using System; using System.Collections.Generic; using System.Text; -namespace Avalonia.Animation +namespace Avalonia.Animation.Utils { - internal static class DoubleHelper + internal static class DoubleUtils { internal static bool AboutEqual(double x, double y) { diff --git a/src/Avalonia.Animation/Helpers/EasingConstants.cs b/src/Avalonia.Animation/Utils/EasingUtils.cs similarity index 85% rename from src/Avalonia.Animation/Helpers/EasingConstants.cs rename to src/Avalonia.Animation/Utils/EasingUtils.cs index b6a52ab4a4..d07ec3cdf4 100644 --- a/src/Avalonia.Animation/Helpers/EasingConstants.cs +++ b/src/Avalonia.Animation/Utils/EasingUtils.cs @@ -3,12 +3,12 @@ using System; -namespace Avalonia.Animation +namespace Avalonia.Animation.Utils { /// /// Helper static class for easing mathematical constants. /// - internal static class EasingConstants + internal static class EasingUtils { /// /// Half of diff --git a/src/Avalonia.Styling/Avalonia.Styling.csproj b/src/Avalonia.Styling/Avalonia.Styling.csproj index 81b2bfd88b..7f39da4801 100644 --- a/src/Avalonia.Styling/Avalonia.Styling.csproj +++ b/src/Avalonia.Styling/Avalonia.Styling.csproj @@ -34,6 +34,7 @@ + \ No newline at end of file diff --git a/src/Avalonia.Styling/Styling/Style.cs b/src/Avalonia.Styling/Styling/Style.cs index 4182ffada3..fe4b77322d 100644 --- a/src/Avalonia.Styling/Styling/Style.cs +++ b/src/Avalonia.Styling/Styling/Style.cs @@ -7,6 +7,7 @@ using System.Collections.Specialized; using System.Reactive.Linq; using Avalonia.Controls; using Avalonia.Metadata; +using Avalonia.Animation; namespace Avalonia.Styling { @@ -20,6 +21,8 @@ namespace Avalonia.Styling private IResourceNode _parent; private IResourceDictionary _resources; + private IList _animations; + /// /// Initializes a new instance of the class. /// @@ -78,6 +81,17 @@ namespace Avalonia.Styling [Content] public IList Setters { get; set; } = new List(); + public IList Animations + { + get + { + return _animations ?? (_animations = new List()); + } + set + { + _animations = value; + } + } /// IResourceNode IResourceNode.ResourceParent => _parent; @@ -91,7 +105,7 @@ namespace Avalonia.Styling /// /// The control that contains this style. May be null. /// - public void Attach(IStyleable control, IStyleHost container) + void IStyle.Attach(IStyleable control, IStyleHost container) { if (Selector != null) { @@ -101,6 +115,11 @@ namespace Avalonia.Styling { var subs = GetSubscriptions(control); + foreach (var animation in Animations) + { + subs.Add(animation.Apply((Animatable)control, match.ObservableResult)); + } + foreach (var setter in Setters) { var sub = setter.Apply(this, control, match.ObservableResult); diff --git a/src/Avalonia.Visuals/Animation/Keyframes/TransformKeyFrames.cs b/src/Avalonia.Visuals/Animation/Keyframes/TransformKeyFrames.cs new file mode 100644 index 0000000000..e8e5ff4d9a --- /dev/null +++ b/src/Avalonia.Visuals/Animation/Keyframes/TransformKeyFrames.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Avalonia.Collections; +using System.ComponentModel; +using Avalonia.Animation.Utils; +using System.Reactive.Linq; +using System.Linq; +using Avalonia.Media; + +namespace Avalonia.Animation.Keyframes +{ + /// + /// Key frames that handles properties. + /// + public class TransformKeyFrames : KeyFrames + { + DoubleKeyFrames childKeyFrames; + + /// + public override IDisposable Apply(Animation animation, Animatable control, IObservable obsMatch) + { + var ctrl = (Visual)control; + + // Check if the AvaloniaProperty is Transform derived. + if (typeof(Transform).IsAssignableFrom(Property.OwnerType)) + { + var renderTransformType = ctrl.RenderTransform.GetType(); + + // It's only 1 transform object so let's target that. + if (renderTransformType == Property.OwnerType) + { + var targetTransform = Convert.ChangeType(ctrl.RenderTransform, Property.OwnerType); + + if (childKeyFrames == null) + { + childKeyFrames = new DoubleKeyFrames(); + + foreach (KeyFrame k in this) + { + childKeyFrames.Add(k); + } + + childKeyFrames.Property = Property; + } + + return childKeyFrames.Apply(animation, ctrl.RenderTransform, obsMatch); + } + if (renderTransformType == typeof(TransformGroup)) + { + foreach (Transform t in ((TransformGroup)ctrl.RenderTransform).Children) + { + if (renderTransformType == Property.OwnerType) + { + + } + } + + // not existing in the transform + + } + } + else + { + throw new InvalidProgramException($"Unsupported property {Property}"); + } + + return null; + } + + /// + public override IDisposable DoInterpolation(Animation animation, Animatable control, Dictionary keyValues) + { + return Timing.GetTimer(animation.Duration, animation.Delay).Subscribe(); + } + } +} diff --git a/src/Avalonia.Visuals/Animation/PointTransition.cs b/src/Avalonia.Visuals/Animation/Transitions/PointTransition.cs similarity index 92% rename from src/Avalonia.Visuals/Animation/PointTransition.cs rename to src/Avalonia.Visuals/Animation/Transitions/PointTransition.cs index f29ae1b9eb..66082dca52 100644 --- a/src/Avalonia.Visuals/Animation/PointTransition.cs +++ b/src/Avalonia.Visuals/Animation/Transitions/PointTransition.cs @@ -5,10 +5,10 @@ using Avalonia.Metadata; using System; using System.Reactive.Linq; -namespace Avalonia.Animation +namespace Avalonia.Animation.Transitions { /// - /// Transition class that handles with types. + /// Transition class that handles with type. /// public class PointTransition : Transition { diff --git a/src/Avalonia.Visuals/Animation/ThicknessTransition.cs b/src/Avalonia.Visuals/Animation/Transitions/ThicknessTransition.cs similarity index 93% rename from src/Avalonia.Visuals/Animation/ThicknessTransition.cs rename to src/Avalonia.Visuals/Animation/Transitions/ThicknessTransition.cs index 4f31d3eb48..9c6d5cc327 100644 --- a/src/Avalonia.Visuals/Animation/ThicknessTransition.cs +++ b/src/Avalonia.Visuals/Animation/Transitions/ThicknessTransition.cs @@ -5,10 +5,10 @@ using Avalonia.Metadata; using System; using System.Reactive.Linq; -namespace Avalonia.Animation +namespace Avalonia.Animation.Transitions { /// - /// Transition class that handles with types. + /// Transition class that handles with type. /// public class ThicknessTransition : Transition { diff --git a/src/Avalonia.Visuals/Properties/AssemblyInfo.cs b/src/Avalonia.Visuals/Properties/AssemblyInfo.cs index 87347d64b1..5456576ef2 100644 --- a/src/Avalonia.Visuals/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Visuals/Properties/AssemblyInfo.cs @@ -8,6 +8,8 @@ using Avalonia.Metadata; [assembly: AssemblyTitle("Avalonia.Visuals")] [assembly: InternalsVisibleTo("Avalonia.Visuals.UnitTests")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Transitions")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Keyframes")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media")] [assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests")] diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/EasingTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/EasingTypeConverter.cs index 851d579581..2dfea4f176 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/EasingTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/EasingTypeConverter.cs @@ -1,7 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using Avalonia.Animation; +using Avalonia.Animation.Easings; using System; using System.ComponentModel; using System.Globalization; diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs index 5f0f8d8d46..64a242cfc6 100644 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs @@ -13,6 +13,7 @@ using Avalonia.Input; using Avalonia.Collections; using Avalonia.Controls.Templates; using Avalonia.Animation; +using Avalonia.Animation.Easings; namespace Avalonia.Markup.Xaml.PortableXaml {