mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 11:56:30 +00:00
Added generic typing to layer properties and keyframes
Restructured the way property input VMs are created
This commit is contained in:
1 parent
39cc8bfbdb
commit
7a3b5dec3e
21 files changed
+342
-155
No files matched your search
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
public class Keyframe
|
||||
{
|
||||
public Layer Layer { get; set; }
|
||||
public LayerProperty Property { get; set; }
|
||||
|
||||
public TimeSpan Position { get; set; }
|
||||
public object Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Exceptions;
|
||||
using Artemis.Core.Extensions;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Models.Profile.LayerShapes;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Plugins.LayerBrush;
|
||||
@@ -14,7 +16,7 @@ namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
public sealed class Layer : ProfileElement
|
||||
{
|
||||
private readonly List<LayerProperty> _properties;
|
||||
private readonly Dictionary<string, BaseLayerProperty> _properties;
|
||||
private LayerShape _layerShape;
|
||||
private List<ArtemisLed> _leds;
|
||||
|
||||
@@ -28,7 +30,7 @@ namespace Artemis.Core.Models.Profile
|
||||
Name = name;
|
||||
|
||||
_leds = new List<ArtemisLed>();
|
||||
_properties = new List<LayerProperty>();
|
||||
_properties = new Dictionary<string, BaseLayerProperty>();
|
||||
|
||||
CreateDefaultProperties();
|
||||
}
|
||||
@@ -44,7 +46,7 @@ namespace Artemis.Core.Models.Profile
|
||||
Order = layerEntity.Order;
|
||||
|
||||
_leds = new List<ArtemisLed>();
|
||||
_properties = new List<LayerProperty>();
|
||||
_properties = new Dictionary<string, BaseLayerProperty>();
|
||||
|
||||
// TODO: Load properties from entity instead of creating the defaults
|
||||
CreateDefaultProperties();
|
||||
@@ -113,32 +115,32 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <summary>
|
||||
/// A collection of all the properties on this layer
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<LayerProperty> Properties => _properties.AsReadOnly();
|
||||
public ReadOnlyCollection<BaseLayerProperty> Properties => _properties.Values.ToList().AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// The anchor point property of this layer, also found in <see cref="Properties" />
|
||||
/// </summary>
|
||||
public LayerProperty AnchorPointProperty { get; private set; }
|
||||
public LayerProperty<SKPoint> AnchorPointProperty { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The position of this layer, also found in <see cref="Properties" />
|
||||
/// </summary>
|
||||
public LayerProperty PositionProperty { get; private set; }
|
||||
public LayerProperty<SKPoint> PositionProperty { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The scale property of this layer, also found in <see cref="Properties" />
|
||||
/// </summary>
|
||||
public LayerProperty ScaleProperty { get; private set; }
|
||||
public LayerProperty<SKSize> ScaleProperty { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The rotation property of this layer, also found in <see cref="Properties" />
|
||||
/// </summary>
|
||||
public LayerProperty RotationProperty { get; private set; }
|
||||
public LayerProperty<int> RotationProperty { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The opacity property of this layer, also found in <see cref="Properties" />
|
||||
/// </summary>
|
||||
public LayerProperty OpacityProperty { get; private set; }
|
||||
public LayerProperty<float> OpacityProperty { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The brush that will fill the <see cref="LayerShape" />.
|
||||
@@ -262,6 +264,62 @@ namespace Artemis.Core.Models.Profile
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
public void AddLayerProperty<T>(LayerProperty<T> layerProperty)
|
||||
{
|
||||
if (_properties.ContainsKey(layerProperty.Id))
|
||||
throw new ArtemisCoreException($"Duplicate property ID detected. Layer already contains a property with ID {layerProperty.Id}.");
|
||||
|
||||
_properties.Add(layerProperty.Id, layerProperty);
|
||||
}
|
||||
|
||||
public void AddLayerProperty(BaseLayerProperty layerProperty)
|
||||
{
|
||||
if (_properties.ContainsKey(layerProperty.Id))
|
||||
throw new ArtemisCoreException($"Duplicate property ID detected. Layer already contains a property with ID {layerProperty.Id}.");
|
||||
|
||||
_properties.Add(layerProperty.Id, layerProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If found, returns the <see cref="LayerProperty{T}"/> matching the provided ID
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the layer property</typeparam>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public LayerProperty<T> GetLayerPropertyById<T>(string id)
|
||||
{
|
||||
if (!_properties.ContainsKey(id))
|
||||
return null;
|
||||
|
||||
var property = _properties[id];
|
||||
if (property.Type != typeof(T))
|
||||
throw new ArtemisCoreException($"Property type mismatch. Expected property {property} to have type {typeof(T)} but it has {property.Type} instead.");
|
||||
return (LayerProperty<T>) _properties[id];
|
||||
}
|
||||
|
||||
private void CreateDefaultProperties()
|
||||
{
|
||||
var transformProperty = new LayerProperty<object>(this, null, "Core.Transform", "Transform", "The default properties collection every layer has, allows you to transform the shape.");
|
||||
AnchorPointProperty = new LayerProperty<SKPoint>(this, transformProperty, "Core.AnchorPoint", "Anchor Point", "The point at which the shape is attached to its position.");
|
||||
PositionProperty = new LayerProperty<SKPoint>(this, transformProperty, "Core.Position", "Position", "The position of the shape.");
|
||||
ScaleProperty = new LayerProperty<SKSize>(this, transformProperty, "Core.Scale", "Scale", "The scale of the shape.") {InputAffix = "%"};
|
||||
RotationProperty = new LayerProperty<int>(this, transformProperty, "Core.Rotation", "Rotation", "The rotation of the shape in degrees.") {InputAffix = "°"};
|
||||
OpacityProperty = new LayerProperty<float>(this, transformProperty, "Core.Opacity", "Opacity", "The opacity of the shape.") {InputAffix = "%"};
|
||||
transformProperty.Children.Add(AnchorPointProperty);
|
||||
transformProperty.Children.Add(PositionProperty);
|
||||
transformProperty.Children.Add(ScaleProperty);
|
||||
transformProperty.Children.Add(RotationProperty);
|
||||
transformProperty.Children.Add(OpacityProperty);
|
||||
|
||||
AddLayerProperty(transformProperty);
|
||||
foreach (var transformPropertyChild in transformProperty.Children)
|
||||
AddLayerProperty(transformPropertyChild);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal void CalculateRenderProperties()
|
||||
{
|
||||
if (!Leds.Any())
|
||||
@@ -291,23 +349,6 @@ namespace Artemis.Core.Models.Profile
|
||||
OnRenderPropertiesUpdated();
|
||||
}
|
||||
|
||||
private void CreateDefaultProperties()
|
||||
{
|
||||
var transformProperty = new LayerProperty(this, null, "Transform", "The default properties collection every layer has, allows you to transform the shape.", null);
|
||||
AnchorPointProperty = new LayerProperty(this, transformProperty, "Anchor Point", "The point at which the shape is attached to its position.", typeof(SKPoint));
|
||||
PositionProperty = new LayerProperty(this, transformProperty, "Position", "The position of the shape.", typeof(SKPoint));
|
||||
ScaleProperty = new LayerProperty(this, transformProperty, "Scale", "The scale of the shape.", typeof(SKSize)) { InputAffix = "%" };
|
||||
RotationProperty = new LayerProperty(this, transformProperty, "Rotation", "The rotation of the shape in degrees.", typeof(int)) {InputAffix = "°" };
|
||||
OpacityProperty = new LayerProperty(this, transformProperty, "Opacity", "The opacity of the shape.", typeof(float)) {InputAffix = "%"};
|
||||
transformProperty.Children.Add(AnchorPointProperty);
|
||||
transformProperty.Children.Add(PositionProperty);
|
||||
transformProperty.Children.Add(ScaleProperty);
|
||||
transformProperty.Children.Add(RotationProperty);
|
||||
transformProperty.Children.Add(OpacityProperty);
|
||||
|
||||
_properties.Add(transformProperty);
|
||||
_properties.AddRange(transformProperty.Children);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
{
|
||||
public class BaseKeyframe
|
||||
{
|
||||
protected BaseKeyframe(Layer layer, BaseLayerProperty property)
|
||||
{
|
||||
Layer = layer;
|
||||
BaseProperty = property;
|
||||
}
|
||||
|
||||
public Layer Layer { get; set; }
|
||||
public TimeSpan Position { get; set; }
|
||||
|
||||
protected BaseLayerProperty BaseProperty { get; }
|
||||
protected object BaseValue { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Core.Exceptions;
|
||||
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
{
|
||||
public abstract class BaseLayerProperty
|
||||
{
|
||||
private object _baseValue;
|
||||
|
||||
protected BaseLayerProperty(Layer layer, BaseLayerProperty parent, string id, string name, string description, Type type)
|
||||
{
|
||||
Layer = layer;
|
||||
Parent = parent;
|
||||
Id = id;
|
||||
Name = name;
|
||||
Description = description;
|
||||
Type = type;
|
||||
|
||||
Children = new List<BaseLayerProperty>();
|
||||
BaseKeyframes = new List<BaseKeyframe>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The layer this property applies to
|
||||
/// </summary>
|
||||
public Layer Layer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The parent property of this property.
|
||||
/// </summary>
|
||||
public BaseLayerProperty Parent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The child properties of this property.
|
||||
/// <remarks>If the layer has children it cannot contain a value or keyframes.</remarks>
|
||||
/// </summary>
|
||||
public List<BaseLayerProperty> Children { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A unique identifier for this property, a layer may not contain two properties with the same ID.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user-friendly name for this property, shown in the UI.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user-friendly description for this property, shown in the UI.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An optional input prefix to show before input elements in the UI.
|
||||
/// </summary>
|
||||
public string InputPrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An optional input affix to show behind input elements in the UI.
|
||||
/// </summary>
|
||||
public string InputAffix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of value this layer property contains.
|
||||
/// </summary>
|
||||
public Type Type { get; set; }
|
||||
|
||||
protected List<BaseKeyframe> BaseKeyframes { get; set; }
|
||||
/// <summary>
|
||||
/// A list of keyframes defining different values of the property in time, this list contains the untyped <see cref="BaseKeyframe"/>.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<BaseKeyframe> UntypedKeyframes => BaseKeyframes.AsReadOnly();
|
||||
|
||||
protected object BaseValue
|
||||
{
|
||||
get => _baseValue;
|
||||
set
|
||||
{
|
||||
if (value != null && value.GetType() != Type)
|
||||
throw new ArtemisCoreException($"Cannot set value of type {value.GetType()} on property {this}, expected type is {Type}.");
|
||||
_baseValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ApplyToEntity()
|
||||
{
|
||||
// Big o' TODO
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(Id)}: {Id}, {nameof(Name)}: {Name}, {nameof(Description)}: {Description}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class Keyframe<T> : BaseKeyframe
|
||||
{
|
||||
public Keyframe(Layer layer, LayerProperty<T> propertyBase) : base(layer, propertyBase)
|
||||
{
|
||||
}
|
||||
|
||||
public LayerProperty<T> Property => (LayerProperty<T>) BaseProperty;
|
||||
|
||||
public T Value
|
||||
{
|
||||
get => (T) BaseValue;
|
||||
set => BaseValue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
{
|
||||
public class LayerProperty<T> : BaseLayerProperty
|
||||
{
|
||||
public LayerProperty(Layer layer, BaseLayerProperty parent, string id, string name, string description) : base(layer, parent, id, name, description, typeof(T))
|
||||
{
|
||||
}
|
||||
|
||||
public T Value
|
||||
{
|
||||
get => (T) BaseValue;
|
||||
set => BaseValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of keyframes defining different values of the property in time, this list contains the strongly typed <see cref="Keyframe{T}"/>
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<Keyframe<T>> Keyframes => BaseKeyframes.Cast<Keyframe<T>>().ToList().AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a keyframe to the property.
|
||||
/// </summary>
|
||||
/// <param name="keyframe">The keyframe to remove</param>
|
||||
public void AddKeyframe(Keyframe<T> keyframe)
|
||||
{
|
||||
BaseKeyframes.Add(keyframe);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a keyframe from the property.
|
||||
/// </summary>
|
||||
/// <param name="keyframe">The keyframe to remove</param>
|
||||
public void RemoveKeyframe(Keyframe<T> keyframe)
|
||||
{
|
||||
BaseKeyframes.Remove(keyframe);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all keyframes from the property.
|
||||
/// </summary>
|
||||
public void ClearKeyframes()
|
||||
{
|
||||
BaseKeyframes.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Core.Exceptions;
|
||||
|
||||
namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
public class LayerProperty
|
||||
{
|
||||
private object _baseValue;
|
||||
|
||||
internal LayerProperty(Layer layer, LayerProperty parent, string name, string description, Type type)
|
||||
{
|
||||
Layer = layer;
|
||||
Parent = parent;
|
||||
Name = name;
|
||||
Description = description;
|
||||
Type = type;
|
||||
|
||||
Children = new List<LayerProperty>();
|
||||
Keyframes = new List<Keyframe>();
|
||||
}
|
||||
|
||||
public Layer Layer { get; }
|
||||
public LayerProperty Parent { get; }
|
||||
public List<LayerProperty> Children { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string InputPrefix { get; set; }
|
||||
public string InputAffix { get; set; }
|
||||
public Type Type { get; set; }
|
||||
|
||||
public object BaseValue
|
||||
{
|
||||
get => _baseValue;
|
||||
set
|
||||
{
|
||||
if (value != null && value.GetType() != Type)
|
||||
throw new ArtemisCoreException($"Cannot set value of type {value.GetType()} on property {Name}, expected type is {Type}.");
|
||||
_baseValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Keyframe> Keyframes { get; set; }
|
||||
|
||||
public void ApplyToEntity()
|
||||
{
|
||||
// Big o' TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user