From e97fc046f59108a8c0d754aa8cb3e005b53a5380 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 29 Apr 2020 19:45:13 +0200 Subject: [PATCH] Core - Added ways for the core to easily access brush properties %*/@ me, dealing with generic types in APIs is tricky --- src/Artemis.Core/Models/Profile/Layer.cs | 22 +++++++-- .../LayerProperties/BaseLayerProperty.cs | 38 ++++++++++++++- .../Profile/LayerProperties/LayerProperty.cs | 45 +++++------------ .../Types/EnumLayerProperty.cs | 7 +-- .../Models/Profile/LayerPropertyGroup.cs | 48 ++++++++++++++++++- .../Plugins/LayerBrush/BaseLayerBrush.cs | 11 +++++ .../Plugins/LayerBrush/LayerBrush.cs | 15 +++++- 7 files changed, 145 insertions(+), 41 deletions(-) diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index 257a63244..19a20ab39 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Artemis.Core.Extensions; +using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Models.Profile.LayerProperties.Attributes; using Artemis.Core.Models.Profile.LayerShapes; using Artemis.Core.Models.Surface; @@ -180,13 +181,28 @@ namespace Artemis.Core.Models.Profile /// public override void Update(double deltaTime) { + if (LayerBrush == null) + return; + General.Update(deltaTime); Transform.Update(deltaTime); + LayerBrush.UpdateProperties(deltaTime); - LayerBrush?.UpdateProperties(deltaTime); - // TODO: Find the last keyframe and if required, reset the properties + var properties = new List(General.GetAllLayerProperties()); + properties.AddRange(Transform.GetAllLayerProperties()); + properties.AddRange(LayerBrush.GetAllLayerProperties()); - LayerBrush?.Update(deltaTime); + // For now, reset all keyframe engines after the last keyframe was hit + // This is a placeholder method of repeating the animation until repeat modes are implemented + var timeLineEnd = properties.Max(p => p.GetLastKeyframePosition()); + if (properties.Any(p => p.TimelineProgress >= timeLineEnd)) + { + General.Override(TimeSpan.Zero); + Transform.Override(TimeSpan.Zero); + LayerBrush.OverrideProperties(TimeSpan.Zero); + } + + LayerBrush.Update(deltaTime); } /// diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs index b8daceb02..e27f82c6c 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs @@ -1,13 +1,46 @@ -using Artemis.Storage.Entities.Profile; +using System; +using System.Collections.Generic; +using Artemis.Storage.Entities.Profile; namespace Artemis.Core.Models.Profile.LayerProperties { + /// + /// For internal use only, to implement your own layer property type, extend instead. + /// public abstract class BaseLayerProperty { /// /// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID /// internal bool IsCoreProperty { get; set; } + internal PropertyEntity PropertyEntity { get; set; } + internal LayerPropertyGroup LayerPropertyGroup { get; set; } + + /// + /// Gets whether keyframes are supported on this property + /// + public bool KeyframesSupported { get; protected set; } + + /// + /// Gets or sets whether keyframes are enabled on this property, has no effect if is + /// False + /// + public bool KeyframesEnabled { get; set; } + + /// + /// Gets or sets whether the property is hidden in the UI + /// + public bool IsHidden { get; set; } + + /// + /// Indicates whether the BaseValue was loaded from storage, useful to check whether a default value must be applied + /// + public bool IsLoadedFromStorage { get; internal set; } + + /// + /// Gets the total progress on the timeline + /// + public TimeSpan TimelineProgress { get; internal set; } /// /// Applies the provided property entity to the layer property by deserializing the JSON base value and keyframe values @@ -21,5 +54,8 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// /// internal abstract void ApplyToEntity(); + + internal abstract List GetKeyframePositions(); + internal abstract TimeSpan GetLastKeyframePosition(); } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs index 2b89dfd8d..1ce9a5ec3 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs @@ -53,38 +53,12 @@ namespace Artemis.Core.Models.Profile.LayerProperties get => !KeyframesEnabled || !KeyframesSupported ? BaseValue : _currentValue; internal set => _currentValue = value; } - - /// - /// Gets whether keyframes are supported on this property - /// - public bool KeyframesSupported { get; internal set; } - - /// - /// Gets or sets whether keyframes are enabled on this property, has no effect if is - /// False - /// - public bool KeyframesEnabled { get; set; } - - /// - /// Gets or sets whether the property is hidden in the UI - /// - public bool IsHidden { get; set; } - - /// - /// Indicates whether the BaseValue was loaded from storage, useful to check whether a default value must be applied - /// - public bool IsLoadedFromStorage { get; internal set; } - + /// /// Gets a read-only list of all the keyframes on this layer property /// public IReadOnlyList> Keyframes => _keyframes.AsReadOnly(); - - /// - /// Gets the total progress on the timeline - /// - public TimeSpan TimelineProgress { get; private set; } - + /// /// Gets the current keyframe in the timeline according to the current progress /// @@ -94,10 +68,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// Gets the next keyframe in the timeline according to the current progress /// public LayerPropertyKeyframe NextKeyframe { get; protected set; } - - internal PropertyEntity PropertyEntity { get; set; } - internal LayerPropertyGroup LayerPropertyGroup { get; set; } - + /// /// Adds a keyframe to the layer property /// @@ -232,6 +203,16 @@ namespace Artemis.Core.Models.Profile.LayerProperties })); } + internal override List GetKeyframePositions() + { + return Keyframes.Select(k => k.Position).ToList(); + } + + internal override TimeSpan GetLastKeyframePosition() + { + return Keyframes.LastOrDefault()?.Position ?? TimeSpan.Zero; + } + #region Events public event EventHandler Updated; diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/Types/EnumLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/Types/EnumLayerProperty.cs index 0dbcf3332..63cfbbfd7 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/Types/EnumLayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/Types/EnumLayerProperty.cs @@ -1,9 +1,10 @@ -using Artemis.Core.Exceptions; +using System; +using Artemis.Core.Exceptions; namespace Artemis.Core.Models.Profile.LayerProperties.Types { - /// - public class EnumLayerProperty : LayerProperty where T : System.Enum + /// + public class EnumLayerProperty : LayerProperty where T : Enum { public EnumLayerProperty() { diff --git a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs index 60b83d7ca..486b36aa2 100644 --- a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs +++ b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using Artemis.Core.Events; +using Artemis.Core.Exceptions; using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Models.Profile.LayerProperties.Attributes; using Artemis.Core.Plugins.Exceptions; @@ -10,13 +13,31 @@ namespace Artemis.Core.Models.Profile { public class LayerPropertyGroup { + private ReadOnlyCollection _allLayerProperties; + + protected LayerPropertyGroup() + { + LayerProperties = new List(); + LayerPropertyGroups = new List(); + } + public bool PropertiesInitialized { get; private set; } /// - /// Used to declare that this property group doesn't belong to a plugin and should use the core plugin GUID + /// Used to declare that this property group doesn't belong to a plugin and should use the core plugin GUID /// internal bool IsCorePropertyGroup { get; set; } + /// + /// A list of all layer properties in this group + /// + internal List LayerProperties { get; set; } + + /// + /// A list of al child groups in this group + /// + internal List LayerPropertyGroups { get; set; } + /// /// Called when all layer properties in this property group have been initialized /// @@ -26,6 +47,10 @@ namespace Artemis.Core.Models.Profile internal void InitializeProperties(ILayerService layerService, Layer layer, string path) { + // Doubt this will happen but let's make sure + if (PropertiesInitialized) + throw new ArtemisCoreException("Layer property group already initialized, wut"); + // Get all properties with a PropertyDescriptionAttribute foreach (var propertyInfo in GetType().GetProperties()) { @@ -38,6 +63,7 @@ namespace Artemis.Core.Models.Profile var instance = (BaseLayerProperty) Activator.CreateInstance(propertyInfo.PropertyType); InitializeProperty(layer, path, instance); propertyInfo.SetValue(this, instance); + LayerProperties.Add(instance); } else { @@ -50,6 +76,7 @@ namespace Artemis.Core.Models.Profile var instance = (LayerPropertyGroup) Activator.CreateInstance(propertyInfo.PropertyType); instance.InitializeProperties(layerService, layer, $"{path}{propertyInfo.Name}."); propertyInfo.SetValue(this, instance); + LayerPropertyGroups.Add(instance); } } } @@ -90,6 +117,25 @@ namespace Artemis.Core.Models.Profile OnPropertyGroupOverriding(new PropertyGroupUpdatingEventArgs(overrideTime)); } + /// + /// Recursively gets all layer properties on this group and any subgroups + /// + /// + internal IReadOnlyCollection GetAllLayerProperties() + { + if (!PropertiesInitialized) + return new List(); + if (_allLayerProperties != null) + return _allLayerProperties; + + var result = new List(LayerProperties); + foreach (var layerPropertyGroup in LayerPropertyGroups) + result.AddRange(layerPropertyGroup.GetAllLayerProperties()); + + _allLayerProperties = result.AsReadOnly(); + return _allLayerProperties; + } + private void InitializeProperty(Layer layer, string path, BaseLayerProperty instance) { var pluginGuid = IsCorePropertyGroup || instance.IsCoreProperty ? Constants.CorePluginInfo.Guid : layer.LayerBrush.PluginInfo.Guid; diff --git a/src/Artemis.Core/Plugins/LayerBrush/BaseLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrush/BaseLayerBrush.cs index 1d831f06f..8e36e0ab3 100644 --- a/src/Artemis.Core/Plugins/LayerBrush/BaseLayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrush/BaseLayerBrush.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Plugins.Models; using Artemis.Core.Services.Interfaces; using SkiaSharp; @@ -66,5 +68,14 @@ namespace Artemis.Core.Plugins.LayerBrush internal virtual void UpdateProperties(double deltaTime) { } + + internal virtual void OverrideProperties(TimeSpan overrideTime) + { + } + + internal virtual IReadOnlyCollection GetAllLayerProperties() + { + return new List(); + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs index 176c2e062..517322571 100644 --- a/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs @@ -1,4 +1,7 @@ -using Artemis.Core.Models.Profile; +using System; +using System.Collections.Generic; +using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Plugins.Exceptions; using Artemis.Core.Services.Interfaces; @@ -60,6 +63,16 @@ namespace Artemis.Core.Plugins.LayerBrush Properties.Update(deltaTime); } + internal override void OverrideProperties(TimeSpan overrideTime) + { + Properties.Override(overrideTime); + } + + internal override IReadOnlyCollection GetAllLayerProperties() + { + return Properties.GetAllLayerProperties(); + } + #endregion } } \ No newline at end of file