Profile editor - Many runtime fixes, UI is back to usable!

This commit is contained in:
SpoinkyNL committed 2020-09-12 23:11:08 +02:00
1 parent db9d9fb4e6
commit 7fff1a593f
38 files changed
+309 -352

No files matched your search

@@ -41,13 +41,13 @@ namespace Artemis.Core
if (DataBinding.LayerProperty.PropertyDescription.MinInputValue is float min)
value = Math.Max(value, min);
ValueSetter?.Invoke(value);
SetExpression?.Invoke(value);
}
/// <inheritdoc />
public override float GetValue()
{
return ValueGetter?.Invoke() ?? 0f;
return GetExpression(DataBinding.LayerProperty.CurrentValue);
}
}
}
@@ -26,13 +26,13 @@ namespace Artemis.Core
/// <inheritdoc />
public override void ApplyValue(object value)
{
ValueSetter?.Invoke(value);
SetExpression?.Invoke(value);
}
/// <inheritdoc />
public override object GetValue()
{
return ValueGetter?.Invoke();
return GetExpression(DataBinding.LayerProperty.CurrentValue);
}
}
}
@@ -3,12 +3,12 @@
namespace Artemis.Core
{
/// <inheritdoc />
public class IntDataBindingConverter : FloatDataBindingConverter<int>
public class IntDataBindingConverter : IntDataBindingConverter<int>
{
}
/// <inheritdoc />
public class IntDataBindingConverter<T> : DataBindingConverter<T, int> where T : ILayerProperty
public class IntDataBindingConverter<T> : DataBindingConverter<T, int>
{
/// <summary>
/// Creates a new instance of the <see cref="IntDataBindingConverter{T}" /> class
@@ -41,13 +41,13 @@ namespace Artemis.Core
/// <inheritdoc />
public override void ApplyValue(int value)
{
ValueSetter?.Invoke(value);
SetExpression?.Invoke(value);
}
/// <inheritdoc />
public override int GetValue()
{
return ValueGetter?.Invoke() ?? 0;
return GetExpression(DataBinding.LayerProperty.CurrentValue);
}
}
}
@@ -13,12 +13,12 @@ namespace Artemis.Core
/// <summary>
/// A dynamically compiled getter pointing to the data bound property
/// </summary>
public Func<TProperty> ValueGetter { get; private set; }
public Func<TLayerProperty, TProperty> GetExpression { get; private set; }
/// <summary>
/// A dynamically compiled setter pointing to the data bound property
/// </summary>
public Action<TProperty> ValueSetter { get; private set; }
public Action<TProperty> SetExpression { get; private set; }
/// <summary>
/// Gets the data binding this converter is applied to
@@ -75,32 +75,12 @@ namespace Artemis.Core
internal void Initialize(DataBinding<TLayerProperty, TProperty> dataBinding)
{
DataBinding = dataBinding;
ValueGetter = CreateValueGetter();
ValueSetter = CreateValueSetter();
GetExpression = dataBinding.Registration.PropertyExpression.Compile();
SetExpression = CreateValueSetter();
OnInitialized();
}
private Func<TProperty> CreateValueGetter()
{
if (DataBinding.TargetProperty?.DeclaringType == null)
return null;
var getterMethod = DataBinding.TargetProperty.GetGetMethod();
if (getterMethod == null)
return null;
var constant = Expression.Constant(DataBinding.LayerProperty);
// The path is null if the registration is applied to the root (LayerProperty.CurrentValue)
var property = DataBinding.Registration.Path == null
? Expression.Property(constant, DataBinding.TargetProperty)
: (MemberExpression) DataBinding.Registration.Path.Split('.').Aggregate<string, Expression>(constant, Expression.Property);
var lambda = Expression.Lambda<Func<TProperty>>(property);
return lambda.Compile();
}
private Action<TProperty> CreateValueSetter()
{
if (DataBinding.TargetProperty?.DeclaringType == null)
@@ -110,10 +90,9 @@ namespace Artemis.Core
if (setterMethod == null)
return null;
var constant = Expression.Constant(DataBinding.LayerProperty);
var propertyValue = Expression.Parameter(typeof(TProperty), "propertyValue");
var body = Expression.Call(constant, setterMethod, propertyValue);
var body = DataBinding.Registration.PropertyExpression;
var lambda = Expression.Lambda<Action<TProperty>>(body, propertyValue);
return lambda.Compile();
}
@@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Artemis.Core
@@ -7,16 +8,13 @@ namespace Artemis.Core
/// <inheritdoc />
public class DataBindingRegistration<TLayerProperty, TProperty> : IDataBindingRegistration
{
internal DataBindingRegistration(
LayerProperty<TLayerProperty> layerProperty,
DataBindingConverter<TLayerProperty, TProperty> converter,
PropertyInfo property,
string path)
internal DataBindingRegistration(LayerProperty<TLayerProperty> layerProperty,
DataBindingConverter<TLayerProperty, TProperty> converter,
Expression<Func<TLayerProperty, TProperty>> propertyExpression)
{
LayerProperty = layerProperty ?? throw new ArgumentNullException(nameof(layerProperty));
Converter = converter ?? throw new ArgumentNullException(nameof(converter));
Property = property ?? throw new ArgumentNullException(nameof(property));
Path = path ?? throw new ArgumentNullException(nameof(path));
PropertyExpression = propertyExpression ?? throw new ArgumentNullException(nameof(propertyExpression));
}
/// <summary>
@@ -24,22 +22,21 @@ namespace Artemis.Core
/// </summary>
public LayerProperty<TLayerProperty> LayerProperty { get; }
/// <summary>
/// Gets the converter that's used by the data binding
/// </summary>
public DataBindingConverter<TLayerProperty, TProperty> Converter { get; }
/// <summary>
/// Gets the expression that that accesses the property
/// </summary>
public Expression<Func<TLayerProperty, TProperty>> PropertyExpression { get; }
/// <summary>
/// Gets the registered property
/// </summary>
public PropertyInfo Property { get; }
/// <summary>
/// Gets the path of the registered property on the layer property
/// </summary>
public string Path { get; }
/// <summary>
/// Gets the data binding created using this registration
/// </summary>
@@ -51,7 +48,7 @@ namespace Artemis.Core
if (DataBinding != null)
return DataBinding;
var dataBinding = LayerProperty.Entity.DataBindingEntities.FirstOrDefault(e => e.TargetProperty == Path);
var dataBinding = LayerProperty.Entity.DataBindingEntities.FirstOrDefault(e => e.TargetProperty == PropertyExpression.ToString());
if (dataBinding == null)
return null;
+16 -4
View File
@@ -64,8 +64,8 @@ namespace Artemis.Core
_leds = new List<ArtemisLed>();
_expandedPropertyGroups = new List<string>();
Initialize();
Load();
Initialize();
}
internal LayerEntity LayerEntity { get; set; }
@@ -148,11 +148,22 @@ namespace Artemis.Core
LayerBrushStore.LayerBrushRemoved += LayerBrushStoreOnLayerBrushRemoved;
// Layers have two hardcoded property groups, instantiate them
var generalAttribute = Attribute.GetCustomAttribute(
GetType().GetProperty(nameof(General)),
typeof(PropertyGroupDescriptionAttribute)
);
var transformAttribute = Attribute.GetCustomAttribute(
GetType().GetProperty(nameof(Transform)),
typeof(PropertyGroupDescriptionAttribute)
);
General.GroupDescription = (PropertyGroupDescriptionAttribute) generalAttribute;
General.Initialize(this, "General.", Constants.CorePluginInfo);
Transform.GroupDescription = (PropertyGroupDescriptionAttribute) transformAttribute;
Transform.Initialize(this, "Transform.", Constants.CorePluginInfo);
General.ShapeType.BaseValueChanged += ShapeTypeOnBaseValueChanged;
ApplyShapeType();
ActivateLayerBrush();
}
#region Storage
@@ -165,8 +176,6 @@ namespace Artemis.Core
Order = LayerEntity.Order;
_expandedPropertyGroups.AddRange(LayerEntity.ExpandedPropertyGroups);
ActivateLayerBrush();
LoadRenderElement();
}
@@ -710,6 +719,9 @@ namespace Artemis.Core
internal void ActivateLayerBrush()
{
var current = General.BrushReference.CurrentValue;
if (current == null)
return;
var descriptor = LayerBrushStore.Get(current.BrushPluginGuid, current.BrushType)?.LayerBrushDescriptor;
descriptor?.CreateInstance(this);
@@ -729,7 +741,7 @@ namespace Artemis.Core
}
#endregion
#region Event handlers
private void LayerBrushStoreOnLayerBrushRemoved(object sender, LayerBrushStoreEvent e)
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Artemis.Storage.Entities.Profile;
namespace Artemis.Core
@@ -20,5 +21,15 @@ namespace Artemis.Core
/// </para>
/// </summary>
void Initialize(RenderProfileElement profileElement, LayerPropertyGroup group, PropertyEntity entity, bool fromStorage, PropertyDescriptionAttribute description);
/// <summary>
/// Returns a list off all data binding registrations
/// </summary>
List<IDataBindingRegistration> GetAllDataBindingRegistrations();
/// <summary>
/// Gets or sets whether the property is hidden in the UI
/// </summary>
bool IsHidden { get; set; }
}
}
@@ -61,9 +61,7 @@ namespace Artemis.Core
private bool _isHidden;
/// <summary>
/// Gets or sets whether the property is hidden in the UI
/// </summary>
/// <inheritdoc />
public bool IsHidden
{
get => _isHidden;
@@ -335,36 +333,21 @@ namespace Artemis.Core
return _dataBindingRegistrations;
}
public void RegisterDataBindingProperty<TProperty>(Expression<Func<T, TProperty>> propertyLambda, DataBindingConverter<T, TProperty> converter)
public void RegisterDataBindingProperty<TProperty>(Expression<Func<T, TProperty>> propertyExpression, DataBindingConverter<T, TProperty> converter)
{
if (_disposed)
throw new ObjectDisposedException("LayerProperty");
// If the lambda references to itself, use the property info of public new T CurrentValue
PropertyInfo propertyInfo;
string path = null;
if (propertyLambda.Parameters[0] == propertyLambda.Body)
propertyInfo = GetType().GetProperties().FirstOrDefault(p => p.Name == nameof(CurrentValue) && p.PropertyType == typeof(T));
else
{
propertyInfo = ReflectionUtilities.GetPropertyInfo(CurrentValue, propertyLambda);
// Deconstruct the lambda
var current = (MemberExpression) propertyLambda.Body;
path = current.Member.Name;
while (current.Expression is MemberExpression memberExpression)
{
path = current.Member.Name + "." + path;
current = memberExpression;
}
}
if (propertyExpression.Body.NodeType != ExpressionType.MemberAccess && propertyExpression.Body.NodeType != ExpressionType.Parameter)
throw new ArtemisCoreException("Provided expression is invalid, it must be 'value => value' or 'value => value.Property'");
if (converter.SupportedType != propertyInfo.PropertyType)
if (converter.SupportedType != propertyExpression.ReturnType)
{
throw new ArtemisCoreException($"Cannot register data binding property for property {propertyInfo.Name} " +
throw new ArtemisCoreException($"Cannot register data binding property for property {PropertyDescription.Name} " +
"because the provided converter does not support the property's type");
}
_dataBindingRegistrations.Add(new DataBindingRegistration<T, TProperty>(this, converter, propertyInfo, path));
_dataBindingRegistrations.Add(new DataBindingRegistration<T, TProperty>(this, converter, propertyExpression));
}
/// <summary>
@@ -432,7 +415,6 @@ namespace Artemis.Core
Entity = entity ?? throw new ArgumentNullException(nameof(entity));
PropertyDescription = description ?? throw new ArgumentNullException(nameof(description));
IsLoadedFromStorage = fromStorage;
LayerPropertyGroup.PropertyGroupUpdating += (sender, args) => Update(args.DeltaTime);
}
@@ -7,6 +7,7 @@ using Artemis.Core.LayerBrushes;
using Artemis.Core.LayerEffects;
using Artemis.Core.Properties;
using Artemis.Storage.Entities.Profile;
using Humanizer;
namespace Artemis.Core
{
@@ -215,6 +216,10 @@ namespace Artemis.Core
if (instance == null)
throw new ArtemisPluginException($"Failed to create instance of layer property at {path + propertyInfo.Name}");
// Ensure the description has a name, if not this is a good point to set it based on the property info
if (string.IsNullOrWhiteSpace(propertyDescription.Name))
propertyDescription.Name = propertyInfo.Name.Humanize();
var entity = GetPropertyEntity(ProfileElement, path + propertyInfo.Name, out var fromStorage);
instance.Initialize(ProfileElement, this, entity, fromStorage, propertyDescription);
propertyInfo.SetValue(this, instance);