mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 11:56:30 +00:00
Conditions - Refactor layer properties WIP
This commit is contained in:
1 parent
f3898b5500
commit
492ee5c8c1
33 files changed
+363
-492
No files matched your search
@@ -0,0 +1,25 @@
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
{
|
||||
public abstract class BaseLayerProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID
|
||||
/// </summary>
|
||||
internal bool IsCoreProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Applies the provided property entity to the layer property by deserializing the JSON base value and keyframe values
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="layerPropertyGroup"></param>
|
||||
internal abstract void ApplyToLayerProperty(PropertyEntity entity, LayerPropertyGroup layerPropertyGroup);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the property to the underlying property entity that was configured when calling
|
||||
/// <see cref="ApplyToLayerProperty" />
|
||||
/// </summary>
|
||||
internal abstract void ApplyToEntity();
|
||||
}
|
||||
}
|
||||
+101
-60
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Exceptions;
|
||||
using Artemis.Core.Utilities;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Newtonsoft.Json;
|
||||
@@ -10,18 +12,19 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
/// <summary>
|
||||
/// Represents a property on a layer. Properties are saved in storage and can optionally be modified from the UI.
|
||||
/// <para>
|
||||
/// Note: You cannot initialize layer properties yourself. If properly placed, the Artemis core will initialize
|
||||
/// Note: You cannot initialize layer properties yourself. If properly placed and annotated, the Artemis core will initialize
|
||||
/// these for you.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of property encapsulated in this layer property</typeparam>
|
||||
public abstract class GenericLayerProperty<T> : LayerProperty
|
||||
public abstract class LayerProperty<T> : BaseLayerProperty
|
||||
{
|
||||
private T _currentValue;
|
||||
private List<LayerPropertyKeyframe<T>> _keyframes;
|
||||
private T _baseValue;
|
||||
private T _currentValue;
|
||||
private bool _isInitialized;
|
||||
private List<LayerPropertyKeyframe<T>> _keyframes;
|
||||
|
||||
protected GenericLayerProperty()
|
||||
protected LayerProperty()
|
||||
{
|
||||
_keyframes = new List<LayerPropertyKeyframe<T>>();
|
||||
}
|
||||
@@ -92,47 +95,8 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
/// </summary>
|
||||
public LayerPropertyKeyframe<T> NextKeyframe { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates the property, moving the timeline forwards by the provided <paramref name="deltaTime" />
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">The amount of time to move the timeline forwards</param>
|
||||
public void Update(double deltaTime)
|
||||
{
|
||||
TimelineProgress = TimelineProgress.Add(TimeSpan.FromSeconds(deltaTime));
|
||||
if (!KeyframesSupported || !KeyframesEnabled)
|
||||
return;
|
||||
|
||||
// The current keyframe is the last keyframe before the current time
|
||||
CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= TimelineProgress);
|
||||
// The next keyframe is the first keyframe that's after the current time
|
||||
NextKeyframe = _keyframes.FirstOrDefault(k => k.Position > TimelineProgress);
|
||||
|
||||
// No need to update the current value if either of the keyframes are null
|
||||
if (CurrentKeyframe == null)
|
||||
CurrentValue = BaseValue;
|
||||
else if (NextKeyframe == null)
|
||||
CurrentValue = CurrentKeyframe.Value;
|
||||
// Only determine progress and current value if both keyframes are present
|
||||
else
|
||||
{
|
||||
var timeDiff = NextKeyframe.Position - CurrentKeyframe.Position;
|
||||
var keyframeProgress = (float) ((TimelineProgress - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds);
|
||||
var keyframeProgressEased = (float) Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction);
|
||||
UpdateCurrentValue(keyframeProgress, keyframeProgressEased);
|
||||
}
|
||||
|
||||
OnUpdated();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the timeline progress to match the provided <paramref name="progress" />
|
||||
/// </summary>
|
||||
/// <param name="progress">The new progress to set the layer property timeline to.</param>
|
||||
public void OverrideProgress(TimeSpan progress)
|
||||
{
|
||||
TimelineProgress = TimeSpan.Zero;
|
||||
Update(progress.TotalSeconds);
|
||||
}
|
||||
internal PropertyEntity PropertyEntity { get; set; }
|
||||
internal LayerPropertyGroup LayerPropertyGroup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a keyframe to the layer property
|
||||
@@ -166,24 +130,106 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
/// <param name="keyframeProgressEased">The current keyframe progress, eased with the current easing function</param>
|
||||
protected abstract void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the property, moving the timeline forwards by the provided <paramref name="deltaTime" />
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">The amount of time to move the timeline forwards</param>
|
||||
internal void Update(double deltaTime)
|
||||
{
|
||||
TimelineProgress = TimelineProgress.Add(TimeSpan.FromSeconds(deltaTime));
|
||||
if (!KeyframesSupported || !KeyframesEnabled)
|
||||
return;
|
||||
|
||||
// The current keyframe is the last keyframe before the current time
|
||||
CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= TimelineProgress);
|
||||
// The next keyframe is the first keyframe that's after the current time
|
||||
NextKeyframe = _keyframes.FirstOrDefault(k => k.Position > TimelineProgress);
|
||||
|
||||
// No need to update the current value if either of the keyframes are null
|
||||
if (CurrentKeyframe == null)
|
||||
CurrentValue = BaseValue;
|
||||
else if (NextKeyframe == null)
|
||||
CurrentValue = CurrentKeyframe.Value;
|
||||
// Only determine progress and current value if both keyframes are present
|
||||
else
|
||||
{
|
||||
var timeDiff = NextKeyframe.Position - CurrentKeyframe.Position;
|
||||
var keyframeProgress = (float) ((TimelineProgress - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds);
|
||||
var keyframeProgressEased = (float) Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction);
|
||||
UpdateCurrentValue(keyframeProgress, keyframeProgressEased);
|
||||
}
|
||||
|
||||
OnUpdated();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the timeline progress to match the provided <paramref name="overrideTime" />
|
||||
/// </summary>
|
||||
/// <param name="overrideTime">The new progress to set the layer property timeline to.</param>
|
||||
internal void OverrideProgress(TimeSpan overrideTime)
|
||||
{
|
||||
TimelineProgress = TimeSpan.Zero;
|
||||
Update(overrideTime.TotalSeconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the keyframes in ascending order by position
|
||||
/// </summary>
|
||||
internal void SortKeyframes()
|
||||
{
|
||||
_keyframes = _keyframes.OrderBy(k => k.Position).ToList();
|
||||
}
|
||||
|
||||
internal override void LoadFromEntity(PropertyEntity entity)
|
||||
internal override void ApplyToLayerProperty(PropertyEntity entity, LayerPropertyGroup layerPropertyGroup)
|
||||
{
|
||||
BaseValue = JsonConvert.DeserializeObject<T>(entity.Value);
|
||||
CurrentValue = BaseValue;
|
||||
// Doubt this will happen but let's make sure
|
||||
if (_isInitialized)
|
||||
throw new ArtemisCoreException("Layer property already initialized, wut");
|
||||
|
||||
_keyframes.Clear();
|
||||
foreach (var keyframeEntity in entity.KeyframeEntities)
|
||||
PropertyEntity = entity;
|
||||
LayerPropertyGroup = layerPropertyGroup;
|
||||
LayerPropertyGroup.PropertyGroupUpdating += (sender, args) => Update(args.DeltaTime);
|
||||
LayerPropertyGroup.PropertyGroupOverriding += (sender, args) => OverrideProgress(args.OverrideTime);
|
||||
|
||||
try
|
||||
{
|
||||
var value = JsonConvert.DeserializeObject<T>(keyframeEntity.Value);
|
||||
var keyframe = new LayerPropertyKeyframe<T>(value, keyframeEntity.Position, (Easings.Functions) keyframeEntity.EasingFunction);
|
||||
_keyframes.Add(keyframe);
|
||||
IsLoadedFromStorage = true;
|
||||
BaseValue = JsonConvert.DeserializeObject<T>(entity.Value);
|
||||
CurrentValue = BaseValue;
|
||||
|
||||
_keyframes.Clear();
|
||||
_keyframes.AddRange(entity.KeyframeEntities.Select(k => new LayerPropertyKeyframe<T>(
|
||||
JsonConvert.DeserializeObject<T>(k.Value),
|
||||
k.Position,
|
||||
(Easings.Functions) k.EasingFunction)
|
||||
));
|
||||
}
|
||||
SortKeyframes();
|
||||
catch (JsonException e)
|
||||
{
|
||||
// TODO: Properly log the JSON exception
|
||||
Debug.WriteLine($"JSON exception while deserializing: {e}");
|
||||
IsLoadedFromStorage = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
SortKeyframes();
|
||||
_isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void ApplyToEntity()
|
||||
{
|
||||
if (_isInitialized)
|
||||
throw new ArtemisCoreException("Layer property is not yet initialized");
|
||||
|
||||
PropertyEntity.Value = JsonConvert.SerializeObject(BaseValue);
|
||||
PropertyEntity.KeyframeEntities.Clear();
|
||||
PropertyEntity.KeyframeEntities.AddRange(Keyframes.Select(k => new KeyframeEntity
|
||||
{
|
||||
Value = JsonConvert.SerializeObject(k.Value),
|
||||
Position = k.Position,
|
||||
EasingFunction = (int) k.EasingFunction
|
||||
}));
|
||||
}
|
||||
|
||||
#region Events
|
||||
@@ -215,9 +261,4 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public abstract class LayerProperty
|
||||
{
|
||||
internal abstract void LoadFromEntity(PropertyEntity entity);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
EasingFunction = easingFunction;
|
||||
}
|
||||
|
||||
public GenericLayerProperty<T> LayerProperty { get; internal set; }
|
||||
public LayerProperty<T> LayerProperty { get; internal set; }
|
||||
public T Value { get; set; }
|
||||
|
||||
public TimeSpan Position
|
||||
|
||||
@@ -4,7 +4,7 @@ using Artemis.Core.Models.Profile.Colors;
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class ColorGradientLayerProperty : GenericLayerProperty<ColorGradient>
|
||||
public class ColorGradientLayerProperty : LayerProperty<ColorGradient>
|
||||
{
|
||||
internal ColorGradientLayerProperty()
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class EnumLayerProperty<T> : GenericLayerProperty<T> where T : System.Enum
|
||||
public class EnumLayerProperty<T> : LayerProperty<T> where T : System.Enum
|
||||
{
|
||||
public EnumLayerProperty()
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class FloatLayerProperty : GenericLayerProperty<float>
|
||||
public class FloatLayerProperty : LayerProperty<float>
|
||||
{
|
||||
internal FloatLayerProperty()
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class IntLayerProperty : GenericLayerProperty<int>
|
||||
public class IntLayerProperty : LayerProperty<int>
|
||||
{
|
||||
internal IntLayerProperty()
|
||||
{
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
||||
/// <summary>
|
||||
/// A special layer property used to configure the selected layer brush
|
||||
/// </summary>
|
||||
public class LayerBrushReferenceLayerProperty : GenericLayerProperty<LayerBrushReference>
|
||||
public class LayerBrushReferenceLayerProperty : LayerProperty<LayerBrushReference>
|
||||
{
|
||||
internal LayerBrushReferenceLayerProperty()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using SkiaSharp;
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class SKColorLayerProperty : GenericLayerProperty<SKColor>
|
||||
public class SKColorLayerProperty : LayerProperty<SKColor>
|
||||
{
|
||||
internal SKColorLayerProperty()
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class SKPointLayerProperty : GenericLayerProperty<SKPoint>
|
||||
public class SKPointLayerProperty : LayerProperty<SKPoint>
|
||||
{
|
||||
internal SKPointLayerProperty()
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class SKSizeLayerProperty : GenericLayerProperty<SKSize>
|
||||
public class SKSizeLayerProperty : LayerProperty<SKSize>
|
||||
{
|
||||
internal SKSizeLayerProperty()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user