Layer properties - Restored much functionality on the reworked VMs

This commit is contained in:
SpoinkyNL committed 2020-05-24 22:05:04 +02:00
1 parent 3d244ff028
commit 8456817a2b
29 files changed
+440 -209

No files matched your search

+29 -20
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Media.Animation;
using Artemis.Core.Extensions;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
@@ -37,6 +38,7 @@ namespace Artemis.Core.Models.Profile
Transform = new LayerTransformProperties {IsCorePropertyGroup = true};
_leds = new List<ArtemisLed>();
General.PropertyGroupInitialized += GeneralOnPropertyGroupInitialized;
}
internal Layer(Profile profile, ProfileElement parent, LayerEntity layerEntity)
@@ -52,6 +54,7 @@ namespace Artemis.Core.Models.Profile
Transform = new LayerTransformProperties {IsCorePropertyGroup = true};
_leds = new List<ArtemisLed>();
General.PropertyGroupInitialized += GeneralOnPropertyGroupInitialized;
}
internal LayerEntity LayerEntity { get; set; }
@@ -147,6 +150,18 @@ namespace Artemis.Core.Models.Profile
#region Shape management
private void GeneralOnPropertyGroupInitialized(object sender, EventArgs e)
{
ApplyShapeType();
General.ShapeType.BaseValueChanged -= ShapeTypeOnBaseValueChanged;
General.ShapeType.BaseValueChanged += ShapeTypeOnBaseValueChanged;
}
private void ShapeTypeOnBaseValueChanged(object sender, EventArgs e)
{
ApplyShapeType();
}
private void ApplyShapeType()
{
switch (General.ShapeType.CurrentValue)
@@ -164,34 +179,21 @@ namespace Artemis.Core.Models.Profile
#endregion
#region Properties
internal void InitializeProperties(ILayerService layerService)
{
PropertiesInitialized = true;
ApplyShapeType();
}
public bool PropertiesInitialized { get; private set; }
#endregion
#region Rendering
/// <inheritdoc />
public override void Update(double deltaTime)
{
if (LayerBrush == null)
if (LayerBrush == null || !LayerBrush.BaseProperties.PropertiesInitialized)
return;
var properties = new List<BaseLayerProperty>(General.GetAllLayerProperties());
properties.AddRange(Transform.GetAllLayerProperties());
properties.AddRange(LayerBrush.BaseProperties.GetAllLayerProperties());
var properties = new List<BaseLayerProperty>(General.GetAllLayerProperties().Where(p => p.BaseKeyframes.Any()));
properties.AddRange(Transform.GetAllLayerProperties().Where(p => p.BaseKeyframes.Any()));
properties.AddRange(LayerBrush.BaseProperties.GetAllLayerProperties().Where(p => p.BaseKeyframes.Any()));
// 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.BaseKeyframes.Max(k => k.Position));
var timeLineEnd = properties.Any() ? properties.Max(p => p.BaseKeyframes.Max(k => k.Position)) : TimeSpan.MaxValue;
if (properties.Any(p => p.TimelineProgress >= timeLineEnd))
{
General.Override(TimeSpan.Zero);
@@ -218,7 +220,7 @@ namespace Artemis.Core.Models.Profile
/// <inheritdoc />
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
{
if (Path == null || LayerShape?.Path == null)
if (Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized)
return;
canvas.Save();
@@ -263,7 +265,8 @@ namespace Artemis.Core.Models.Profile
canvas.Scale(sizeProperty.Width / 100f, sizeProperty.Height / 100f, anchorPosition.X, anchorPosition.Y);
canvas.Translate(x, y);
LayerBrush?.Render(canvas, canvasInfo, new SKPath(LayerShape.Path), paint);
if (LayerBrush != null && LayerBrush.BaseProperties.PropertiesInitialized)
LayerBrush.Render(canvas, canvasInfo, new SKPath(LayerShape.Path), paint);
}
private void ClipRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
@@ -405,6 +408,7 @@ namespace Artemis.Core.Models.Profile
public event EventHandler RenderPropertiesUpdated;
public event EventHandler ShapePropertiesUpdated;
public event EventHandler LayerBrushUpdated;
private void OnRenderPropertiesUpdated()
{
@@ -416,6 +420,11 @@ namespace Artemis.Core.Models.Profile
ShapePropertiesUpdated?.Invoke(this, EventArgs.Empty);
}
internal void OnLayerBrushUpdated()
{
LayerBrushUpdated?.Invoke(this, EventArgs.Empty);
}
#endregion
}
@@ -9,10 +9,17 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// </summary>
public abstract class BaseLayerProperty
{
private bool _keyframesEnabled;
internal BaseLayerProperty()
{
}
/// <summary>
/// The layer this property applies to
/// </summary>
public Layer Layer { get; internal set; }
/// <summary>
/// The parent group of this layer property, set after construction
/// </summary>
@@ -21,13 +28,22 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// <summary>
/// Gets whether keyframes are supported on this property
/// </summary>
public bool KeyframesSupported { get; protected set; }
public bool KeyframesSupported { get; protected set; } = true;
/// <summary>
/// Gets or sets whether keyframes are enabled on this property, has no effect if <see cref="KeyframesSupported" /> is
/// False
/// </summary>
public bool KeyframesEnabled { get; set; }
public bool KeyframesEnabled
{
get => _keyframesEnabled;
set
{
if (_keyframesEnabled == value) return;
_keyframesEnabled = value;
OnKeyframesToggled();
}
}
/// <summary>
/// Gets or sets whether the property is hidden in the UI
@@ -57,17 +73,73 @@ namespace Artemis.Core.Models.Profile.LayerProperties
internal PropertyEntity PropertyEntity { get; set; }
internal LayerPropertyGroup LayerPropertyGroup { 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);
/// <param name="fromStorage"></param>
internal abstract void ApplyToLayerProperty(PropertyEntity entity, LayerPropertyGroup layerPropertyGroup, bool fromStorage);
/// <summary>
/// Saves the property to the underlying property entity that was configured when calling
/// <see cref="ApplyToLayerProperty" />
/// </summary>
internal abstract void ApplyToEntity();
#region Events
/// <summary>
/// Occurs once every frame when the layer property is updated
/// </summary>
public event EventHandler Updated;
/// <summary>
/// Occurs when the base value of the layer property was updated
/// </summary>
public event EventHandler BaseValueChanged;
/// <summary>
/// Occurs when keyframes are enabled/disabled
/// </summary>
public event EventHandler KeyframesToggled;
/// <summary>
/// Occurs when a new keyframe was added to the layer property
/// </summary>
public event EventHandler KeyframeAdded;
/// <summary>
/// Occurs when a keyframe was removed from the layer property
/// </summary>
public event EventHandler KeyframeRemoved;
protected virtual void OnUpdated()
{
Updated?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnBaseValueChanged()
{
BaseValueChanged?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnKeyframesToggled()
{
KeyframesToggled?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnKeyframeAdded()
{
KeyframeAdded?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnKeyframeRemoved()
{
KeyframeRemoved?.Invoke(this, EventArgs.Empty);
}
#endregion
}
}
@@ -180,12 +180,13 @@ namespace Artemis.Core.Models.Profile.LayerProperties
// 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);
// Keyframes are sorted by position so we can safely assume the next keyframe's position is after the current
var nextIndex = _keyframes.IndexOf(CurrentKeyframe) + 1;
NextKeyframe = _keyframes.Count > nextIndex ? _keyframes[nextIndex] : null;
// No need to update the current value if either of the keyframes are null
if (CurrentKeyframe == null)
CurrentValue = BaseValue;
CurrentValue = _keyframes.Any() ? _keyframes[0].Value : BaseValue;
else if (NextKeyframe == null)
CurrentValue = CurrentKeyframe.Value;
// Only determine progress and current value if both keyframes are present
@@ -218,7 +219,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
_keyframes = _keyframes.OrderBy(k => k.Position).ToList();
}
internal override void ApplyToLayerProperty(PropertyEntity entity, LayerPropertyGroup layerPropertyGroup)
internal override void ApplyToLayerProperty(PropertyEntity entity, LayerPropertyGroup layerPropertyGroup, bool fromStorage)
{
// Doubt this will happen but let's make sure
if (_isInitialized)
@@ -231,8 +232,10 @@ namespace Artemis.Core.Models.Profile.LayerProperties
try
{
IsLoadedFromStorage = true;
BaseValue = JsonConvert.DeserializeObject<T>(entity.Value);
if (entity.Value != null)
BaseValue = JsonConvert.DeserializeObject<T>(entity.Value);
IsLoadedFromStorage = fromStorage;
CurrentValue = BaseValue;
KeyframesEnabled = entity.KeyframesEnabled;
@@ -259,7 +262,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
internal override void ApplyToEntity()
{
if (_isInitialized)
if (!_isInitialized)
throw new ArtemisCoreException("Layer property is not yet initialized");
PropertyEntity.Value = JsonConvert.SerializeObject(BaseValue);
@@ -272,49 +275,5 @@ namespace Artemis.Core.Models.Profile.LayerProperties
EasingFunction = (int) k.EasingFunction
}));
}
#region Events
/// <summary>
/// Occurs once every frame when the layer property is updated
/// </summary>
public event EventHandler Updated;
/// <summary>
/// Occurs when the base value of the layer property was updated
/// </summary>
public event EventHandler BaseValueChanged;
/// <summary>
/// Occurs when a new keyframe was added to the layer property
/// </summary>
public event EventHandler KeyframeAdded;
/// <summary>
/// Occurs when a keyframe was removed from the layer property
/// </summary>
public event EventHandler KeyframeRemoved;
protected virtual void OnUpdated()
{
Updated?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnBaseValueChanged()
{
BaseValueChanged?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnKeyframeAdded()
{
KeyframeAdded?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnKeyframeRemoved()
{
KeyframeRemoved?.Invoke(this, EventArgs.Empty);
}
#endregion
}
}
@@ -2,12 +2,14 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Artemis.Core.Annotations;
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;
using Artemis.Core.Services.Interfaces;
using Artemis.Storage.Entities.Profile;
namespace Artemis.Core.Models.Profile
{
@@ -23,6 +25,11 @@ namespace Artemis.Core.Models.Profile
_layerPropertyGroups = new List<LayerPropertyGroup>();
}
/// <summary>
/// The layer this property group applies to
/// </summary>
public Layer Layer { get; internal set; }
/// <summary>
/// The parent group of this layer property group, set after construction
/// </summary>
@@ -60,12 +67,16 @@ namespace Artemis.Core.Models.Profile
{
}
internal void InitializeProperties(ILayerService layerService, Layer layer, string path)
internal void InitializeProperties(ILayerService layerService, Layer layer, [NotNull] string path)
{
if (path == null)
throw new ArgumentNullException(nameof(path));
// Doubt this will happen but let's make sure
if (PropertiesInitialized)
throw new ArtemisCoreException("Layer property group already initialized, wut");
Layer = layer;
// Get all properties with a PropertyDescriptionAttribute
foreach (var propertyInfo in GetType().GetProperties())
{
@@ -77,7 +88,8 @@ namespace Artemis.Core.Models.Profile
var instance = (BaseLayerProperty) Activator.CreateInstance(propertyInfo.PropertyType, true);
instance.Parent = this;
InitializeProperty(layer, path, instance);
instance.Layer = layer;
InitializeProperty(layer, path + propertyInfo.Name, instance);
propertyInfo.SetValue(this, instance);
_layerProperties.Add(instance);
}
@@ -100,6 +112,8 @@ namespace Artemis.Core.Models.Profile
OnPropertiesInitialized();
PropertiesInitialized = true;
OnPropertyGroupInitialized();
}
internal void ApplyToEntity()
@@ -110,12 +124,16 @@ namespace Artemis.Core.Models.Profile
var propertyDescription = Attribute.GetCustomAttribute(propertyInfo, typeof(PropertyDescriptionAttribute));
if (propertyDescription != null)
{
var layerProperty = (BaseLayerProperty) propertyInfo.GetValue(this);
layerProperty.ApplyToEntity();
}
else
{
var propertyGroupDescription = Attribute.GetCustomAttribute(propertyInfo, typeof(PropertyGroupDescriptionAttribute));
if (propertyGroupDescription != null)
{
var layerPropertyGroup = (LayerPropertyGroup) propertyInfo.GetValue(this);
layerPropertyGroup.ApplyToEntity();
}
}
}
@@ -157,14 +175,22 @@ namespace Artemis.Core.Models.Profile
{
var pluginGuid = IsCorePropertyGroup || instance.IsCoreProperty ? Constants.CorePluginInfo.Guid : layer.LayerBrush.PluginInfo.Guid;
var entity = layer.LayerEntity.PropertyEntities.FirstOrDefault(p => p.PluginGuid == pluginGuid && p.Path == path);
if (entity != null)
instance.ApplyToLayerProperty(entity, this);
var fromStorage = true;
if (entity == null)
{
fromStorage = false;
entity = new PropertyEntity {PluginGuid = pluginGuid, Path = path};
layer.LayerEntity.PropertyEntities.Add(entity);
}
instance.ApplyToLayerProperty(entity, this, fromStorage);
}
#region Events
internal event EventHandler<PropertyGroupUpdatingEventArgs> PropertyGroupUpdating;
internal event EventHandler<PropertyGroupUpdatingEventArgs> PropertyGroupOverriding;
public event EventHandler PropertyGroupInitialized;
internal virtual void OnPropertyGroupUpdating(PropertyGroupUpdatingEventArgs e)
{
@@ -177,5 +203,10 @@ namespace Artemis.Core.Models.Profile
}
#endregion
protected virtual void OnPropertyGroupInitialized()
{
PropertyGroupInitialized?.Invoke(this, EventArgs.Empty);
}
}
}
@@ -51,6 +51,7 @@ namespace Artemis.Core.Plugins.LayerBrush
internal override void InitializeProperties(ILayerService layerService, string path)
{
Properties = Activator.CreateInstance<T>();
Properties.InitializeProperties(layerService, Layer, path);
OnPropertiesInitialized();
PropertiesInitialized = true;
+6 -7
View File
@@ -27,8 +27,8 @@ namespace Artemis.Core.Services
var layer = new Layer(profile, parent, name);
// Layers have two hardcoded property groups, instantiate them
layer.General.InitializeProperties(this, layer, null);
layer.Transform.InitializeProperties(this, layer, null);
layer.General.InitializeProperties(this, layer, "General.");
layer.Transform.InitializeProperties(this, layer, "Transform.");
// With the properties loaded, the layer brush can be instantiated
InstantiateLayerBrush(layer);
@@ -58,11 +58,10 @@ namespace Artemis.Core.Services
new ConstructorArgument("layer", layer),
new ConstructorArgument("descriptor", descriptor)
};
var layerBrush = (BaseLayerBrush) _kernel.Get(descriptor.LayerBrushType, arguments);
layerBrush.InitializeProperties(this, null);
layer.LayerBrush = layerBrush;
return layerBrush;
layer.LayerBrush = (BaseLayerBrush)_kernel.Get(descriptor.LayerBrushType, arguments); ;
layer.LayerBrush.InitializeProperties(this, "LayerBrush.");
layer.OnLayerBrushUpdated();
return layer.LayerBrush;
}
public void RemoveLayerBrush(Layer layer)
@@ -93,8 +93,8 @@ namespace Artemis.Core.Services.Storage
module.ChangeActiveProfile(profile, _surfaceService.ActiveSurface);
if (profile != null)
{
InitializeCoreProperties(profile);
InstantiateProfileLayerBrushes(profile);
InitializeLayerProperties(profile);
InstantiateLayerBrushes(profile);
}
}
@@ -159,18 +159,18 @@ namespace Artemis.Core.Services.Storage
_logger.Debug("Redo profile update - Success");
}
private void InitializeCoreProperties(Profile profile)
private void InitializeLayerProperties(Profile profile)
{
foreach (var layer in profile.GetAllLayers().Where(l => l.LayerBrush == null))
{
if (!layer.General.PropertiesInitialized)
layer.General.InitializeProperties(_layerService, layer, null);
layer.General.InitializeProperties(_layerService, layer, "General.");
if (!layer.Transform.PropertiesInitialized)
layer.Transform.InitializeProperties(_layerService, layer, null);
layer.Transform.InitializeProperties(_layerService, layer, "Transform.");
};
}
private void InstantiateProfileLayerBrushes(Profile profile)
private void InstantiateLayerBrushes(Profile profile)
{
// Only instantiate brushes for layers without an existing brush instance
foreach (var layer in profile.GetAllLayers().Where(l => l.LayerBrush == null))
@@ -188,7 +188,7 @@ namespace Artemis.Core.Services.Storage
{
var profileModules = _pluginService.GetPluginsOfType<ProfileModule>();
foreach (var profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList())
InstantiateProfileLayerBrushes(profileModule.ActiveProfile);
InstantiateLayerBrushes(profileModule.ActiveProfile);
}
#region Event handlers