mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Profile editor - Many runtime fixes, UI is back to usable!
This commit is contained in:
1 parent
db9d9fb4e6
commit
7fff1a593f
38 files changed
+309
-352
No files matched your search
+2
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user