mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Merge branch 'development'
This commit is contained in:
commit
f56186b1d8
@ -36,9 +36,6 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
public override void ApplyValue(float value)
|
||||
{
|
||||
if (ValueTypeSetExpression == null)
|
||||
return;
|
||||
|
||||
if (DataBinding!.LayerProperty.PropertyDescription.MaxInputValue is float max)
|
||||
value = Math.Min(value, max);
|
||||
if (DataBinding!.LayerProperty.PropertyDescription.MinInputValue is float min)
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
internal BoolLayerProperty()
|
||||
{
|
||||
KeyframesSupported = false;
|
||||
RegisterDataBindingProperty(b => b, new GeneralDataBindingConverter<bool>());
|
||||
RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, new GeneralDataBindingConverter<bool>(), "Value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -1,17 +1,43 @@
|
||||
namespace Artemis.Core
|
||||
using System.ComponentModel;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class ColorGradientLayerProperty : LayerProperty<ColorGradient>
|
||||
{
|
||||
private ColorGradient? _subscribedGradient;
|
||||
|
||||
internal ColorGradientLayerProperty()
|
||||
{
|
||||
KeyframesSupported = false;
|
||||
DataBindingsSupported = false;
|
||||
DataBindingsSupported = true;
|
||||
DefaultValue = new ColorGradient();
|
||||
|
||||
|
||||
CurrentValueSet += OnCurrentValueSet;
|
||||
}
|
||||
|
||||
private void CreateDataBindingRegistrations()
|
||||
{
|
||||
ClearDataBindingProperties();
|
||||
if (CurrentValue == null)
|
||||
return;
|
||||
|
||||
for (int index = 0; index < CurrentValue.Stops.Count; index++)
|
||||
{
|
||||
int stopIndex = index;
|
||||
|
||||
void Setter(SKColor value)
|
||||
{
|
||||
CurrentValue.Stops[stopIndex].Color = value;
|
||||
CurrentValue.OnColorValuesUpdated();
|
||||
}
|
||||
|
||||
RegisterDataBindingProperty(() => CurrentValue.Stops[stopIndex].Color, Setter, new ColorStopDataBindingConverter(), $"Color #{stopIndex + 1}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Implicitly converts an <see cref="ColorGradientLayerProperty" /> to a <see cref="ColorGradient" />
|
||||
/// </summary>
|
||||
@ -31,6 +57,22 @@
|
||||
// Don't allow color gradients to be null
|
||||
if (BaseValue == null)
|
||||
BaseValue = DefaultValue ?? new ColorGradient();
|
||||
|
||||
if (_subscribedGradient != BaseValue)
|
||||
{
|
||||
if (_subscribedGradient != null)
|
||||
_subscribedGradient.PropertyChanged -= SubscribedGradientOnPropertyChanged;
|
||||
_subscribedGradient = BaseValue;
|
||||
_subscribedGradient.PropertyChanged += SubscribedGradientOnPropertyChanged;
|
||||
}
|
||||
|
||||
CreateDataBindingRegistrations();
|
||||
}
|
||||
|
||||
private void SubscribedGradientOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (CurrentValue.Stops.Count != GetAllDataBindingRegistrations().Count)
|
||||
CreateDataBindingRegistrations();
|
||||
}
|
||||
|
||||
#region Overrides of LayerProperty<ColorGradient>
|
||||
@ -41,10 +83,31 @@
|
||||
// Don't allow color gradients to be null
|
||||
if (BaseValue == null)
|
||||
BaseValue = DefaultValue ?? new ColorGradient();
|
||||
|
||||
|
||||
base.OnInitialize();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal class ColorStopDataBindingConverter : DataBindingConverter<ColorGradient, SKColor>
|
||||
{
|
||||
public ColorStopDataBindingConverter()
|
||||
{
|
||||
SupportsInterpolate = true;
|
||||
SupportsSum = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SKColor Sum(SKColor a, SKColor b)
|
||||
{
|
||||
return a.Sum(b);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SKColor Interpolate(SKColor a, SKColor b, double progress)
|
||||
{
|
||||
return a.Interpolate(b, (float) progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,7 @@
|
||||
{
|
||||
internal FloatLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(value => value, new FloatDataBindingConverter());
|
||||
RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, new FloatDataBindingConverter(), "Value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
{
|
||||
internal FloatRangeLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(range => range.Start, new FloatDataBindingConverter<FloatRange>());
|
||||
RegisterDataBindingProperty(range => range.End, new FloatDataBindingConverter<FloatRange>());
|
||||
RegisterDataBindingProperty(() => CurrentValue.Start, value => CurrentValue.Start = value, new FloatDataBindingConverter<FloatRange>(), "Start");
|
||||
RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue.End = value, new FloatDataBindingConverter<FloatRange>(), "End");
|
||||
|
||||
CurrentValueSet += OnCurrentValueSet;
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ namespace Artemis.Core
|
||||
{
|
||||
internal IntLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(value => value, new IntDataBindingConverter());
|
||||
RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, new IntDataBindingConverter(), "Value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
{
|
||||
internal IntRangeLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(range => range.Start, new IntDataBindingConverter<IntRange>());
|
||||
RegisterDataBindingProperty(range => range.End, new IntDataBindingConverter<IntRange>());
|
||||
RegisterDataBindingProperty(() => CurrentValue.Start, value => CurrentValue.Start = value, new IntDataBindingConverter<IntRange>(), "Start");
|
||||
RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue.End = value, new IntDataBindingConverter<IntRange>(), "End");
|
||||
|
||||
CurrentValueSet += OnCurrentValueSet;
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ namespace Artemis.Core
|
||||
{
|
||||
internal SKColorLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(value => value, new SKColorDataBindingConverter());
|
||||
RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, new SKColorDataBindingConverter(), "Value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -7,8 +7,8 @@ namespace Artemis.Core
|
||||
{
|
||||
internal SKPointLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(point => point.X, new FloatDataBindingConverter<SKPoint>());
|
||||
RegisterDataBindingProperty(point => point.Y, new FloatDataBindingConverter<SKPoint>());
|
||||
RegisterDataBindingProperty(() => CurrentValue.X, value => CurrentValue = new SKPoint(value, CurrentValue.Y), new FloatDataBindingConverter<SKPoint>(), "X");
|
||||
RegisterDataBindingProperty(() => CurrentValue.Y, value => CurrentValue = new SKPoint(CurrentValue.X, value), new FloatDataBindingConverter<SKPoint>(), "Y");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -7,8 +7,8 @@ namespace Artemis.Core
|
||||
{
|
||||
internal SKSizeLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(size => size.Height, new FloatDataBindingConverter<SKSize>());
|
||||
RegisterDataBindingProperty(size => size.Width, new FloatDataBindingConverter<SKSize>());
|
||||
RegisterDataBindingProperty(() => CurrentValue.Width, (value) => CurrentValue = new SKSize(value, CurrentValue.Height), new FloatDataBindingConverter<SKSize>(), "Width");
|
||||
RegisterDataBindingProperty(() => CurrentValue.Height, (value) => CurrentValue = new SKSize(CurrentValue.Width, value), new FloatDataBindingConverter<SKSize>(), "Height");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -97,7 +97,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public Type? GetTargetType()
|
||||
{
|
||||
return Registration?.PropertyExpression.ReturnType;
|
||||
return Registration?.Getter.Method.ReturnType;
|
||||
}
|
||||
|
||||
private void ResetEasing(TProperty value)
|
||||
@ -272,7 +272,7 @@ namespace Artemis.Core
|
||||
throw new ObjectDisposedException("DataBinding");
|
||||
|
||||
// General
|
||||
DataBindingRegistration<TLayerProperty, TProperty>? registration = LayerProperty.GetDataBindingRegistration<TProperty>(Entity.TargetExpression);
|
||||
DataBindingRegistration<TLayerProperty, TProperty>? registration = LayerProperty.GetDataBindingRegistration<TProperty>(Entity.Identifier);
|
||||
if (registration != null)
|
||||
ApplyRegistration(registration);
|
||||
|
||||
@ -293,7 +293,7 @@ namespace Artemis.Core
|
||||
|
||||
// Don't save an invalid state
|
||||
if (Registration != null)
|
||||
Entity.TargetExpression = Registration.PropertyExpression.ToString();
|
||||
Entity.Identifier = Registration.DisplayName;
|
||||
|
||||
Entity.EasingTime = EasingTime;
|
||||
Entity.EasingFunction = (int) EasingFunction;
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
@ -10,21 +8,6 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public abstract class DataBindingConverter<TLayerProperty, TProperty> : IDataBindingConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a dynamically compiled getter pointing to the data bound property
|
||||
/// </summary>
|
||||
public Func<TLayerProperty, TProperty>? GetExpression { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dynamically compiled setter pointing to the data bound property used for value types
|
||||
/// </summary>
|
||||
public Action<TProperty>? ValueTypeSetExpression { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dynamically compiled setter pointing to the data bound property used for reference types
|
||||
/// </summary>
|
||||
public Action<TLayerProperty, TProperty>? ReferenceTypeSetExpression { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data binding this converter is applied to
|
||||
/// </summary>
|
||||
@ -40,9 +23,6 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public bool SupportsInterpolate { get; protected set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Type SupportedType => typeof(TProperty);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the sum of <paramref name="a" /> and <paramref name="b" />
|
||||
/// </summary>
|
||||
@ -65,12 +45,9 @@ namespace Artemis.Core
|
||||
/// <param name="value"></param>
|
||||
public virtual void ApplyValue(TProperty value)
|
||||
{
|
||||
if (DataBinding == null)
|
||||
if (DataBinding?.Registration == null)
|
||||
throw new ArtemisCoreException("Data binding converter is not yet initialized");
|
||||
if (ReferenceTypeSetExpression != null)
|
||||
ReferenceTypeSetExpression(DataBinding.LayerProperty.CurrentValue, value);
|
||||
else if (ValueTypeSetExpression != null)
|
||||
ValueTypeSetExpression(value);
|
||||
DataBinding.Registration.Setter(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -78,9 +55,9 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public virtual TProperty GetValue()
|
||||
{
|
||||
if (DataBinding == null || GetExpression == null)
|
||||
if (DataBinding?.Registration == null)
|
||||
throw new ArtemisCoreException("Data binding converter is not yet initialized");
|
||||
return GetExpression(DataBinding.LayerProperty.CurrentValue);
|
||||
return DataBinding.Registration.Getter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -104,83 +81,10 @@ namespace Artemis.Core
|
||||
throw new ArtemisCoreException("Cannot initialize a data binding converter for a data binding without a registration");
|
||||
|
||||
DataBinding = dataBinding;
|
||||
GetExpression = dataBinding.Registration.PropertyExpression.Compile();
|
||||
CreateSetExpression();
|
||||
|
||||
OnInitialized();
|
||||
}
|
||||
|
||||
private void CreateSetExpression()
|
||||
{
|
||||
// If the registration does not point towards a member of LayerProperty<T>.CurrentValue, assign directly to LayerProperty<T>.CurrentValue
|
||||
if (DataBinding!.Registration?.Member == null)
|
||||
{
|
||||
CreateSetCurrentValueExpression();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the member of LayerProperty<T>.CurrentValue has a setter
|
||||
MethodInfo? setterMethod = null;
|
||||
if (DataBinding.Registration.Member is PropertyInfo propertyInfo)
|
||||
setterMethod = propertyInfo.GetSetMethod();
|
||||
// If there is no setter, the built-in data binding cannot do its job, stay null
|
||||
if (setterMethod == null)
|
||||
return;
|
||||
|
||||
// If LayerProperty<T>.CurrentValue is a value type, assign it directly to LayerProperty<T>.CurrentValue after applying the changes
|
||||
if (typeof(TLayerProperty).IsValueType)
|
||||
CreateSetValueTypeExpression();
|
||||
// If it is a reference type it can safely be updated by its reference
|
||||
else
|
||||
CreateSetReferenceTypeExpression();
|
||||
}
|
||||
|
||||
private void CreateSetReferenceTypeExpression()
|
||||
{
|
||||
if (DataBinding!.Registration?.Member == null)
|
||||
throw new ArtemisCoreException("Cannot create value setter for data binding without a registration");
|
||||
|
||||
ParameterExpression propertyValue = Expression.Parameter(typeof(TProperty), "propertyValue");
|
||||
ParameterExpression parameter = Expression.Parameter(typeof(TLayerProperty), "currentValue");
|
||||
MemberExpression memberAccess = Expression.MakeMemberAccess(parameter, DataBinding.Registration.Member);
|
||||
BinaryExpression assignment = Expression.Assign(memberAccess, propertyValue);
|
||||
Expression<Action<TLayerProperty, TProperty>> referenceTypeLambda = Expression.Lambda<Action<TLayerProperty, TProperty>>(assignment, parameter, propertyValue);
|
||||
|
||||
ReferenceTypeSetExpression = referenceTypeLambda.Compile();
|
||||
}
|
||||
|
||||
private void CreateSetValueTypeExpression()
|
||||
{
|
||||
if (DataBinding!.Registration?.Member == null)
|
||||
throw new ArtemisCoreException("Cannot create value setter for data binding without a registration");
|
||||
|
||||
ParameterExpression propertyValue = Expression.Parameter(typeof(TProperty), "propertyValue");
|
||||
ParameterExpression variableCurrent = Expression.Variable(typeof(TLayerProperty), "current");
|
||||
ConstantExpression layerProperty = Expression.Constant(DataBinding.LayerProperty);
|
||||
MemberExpression layerPropertyMemberAccess = Expression.MakeMemberAccess(layerProperty,
|
||||
DataBinding.LayerProperty.GetType().GetMember(nameof(DataBinding.LayerProperty.CurrentValue))[0]);
|
||||
|
||||
BlockExpression body = Expression.Block(
|
||||
new[] {variableCurrent},
|
||||
Expression.Assign(variableCurrent, layerPropertyMemberAccess),
|
||||
Expression.Assign(Expression.MakeMemberAccess(variableCurrent, DataBinding.Registration.Member), propertyValue),
|
||||
Expression.Assign(layerPropertyMemberAccess, variableCurrent)
|
||||
);
|
||||
|
||||
Expression<Action<TProperty>> valueTypeLambda = Expression.Lambda<Action<TProperty>>(body, propertyValue);
|
||||
ValueTypeSetExpression = valueTypeLambda.Compile();
|
||||
}
|
||||
|
||||
private void CreateSetCurrentValueExpression()
|
||||
{
|
||||
ParameterExpression propertyValue = Expression.Parameter(typeof(TProperty), "propertyValue");
|
||||
ConstantExpression layerProperty = Expression.Constant(DataBinding!.LayerProperty);
|
||||
MemberExpression layerPropertyMemberAccess = Expression.MakeMemberAccess(layerProperty,
|
||||
DataBinding.LayerProperty.GetType().GetMember(nameof(DataBinding.LayerProperty.CurrentValue))[0]);
|
||||
|
||||
BinaryExpression body = Expression.Assign(layerPropertyMemberAccess, propertyValue);
|
||||
Expression<Action<TProperty>> lambda = Expression.Lambda<Action<TProperty>>(body, propertyValue);
|
||||
ValueTypeSetExpression = lambda.Compile();
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public Type SupportedType => typeof(TProperty);
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Artemis.Storage.Entities.Profile.DataBindings;
|
||||
|
||||
namespace Artemis.Core
|
||||
@ -9,16 +7,14 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
public class DataBindingRegistration<TLayerProperty, TProperty> : IDataBindingRegistration
|
||||
{
|
||||
internal DataBindingRegistration(LayerProperty<TLayerProperty> layerProperty,
|
||||
DataBindingConverter<TLayerProperty, TProperty> converter,
|
||||
Expression<Func<TLayerProperty, TProperty>> propertyExpression)
|
||||
internal DataBindingRegistration(LayerProperty<TLayerProperty> layerProperty, DataBindingConverter<TLayerProperty, TProperty> converter,
|
||||
Func<TProperty> getter, Action<TProperty> setter, string displayName)
|
||||
{
|
||||
LayerProperty = layerProperty ?? throw new ArgumentNullException(nameof(layerProperty));
|
||||
Converter = converter ?? throw new ArgumentNullException(nameof(converter));
|
||||
PropertyExpression = propertyExpression ?? throw new ArgumentNullException(nameof(propertyExpression));
|
||||
|
||||
if (propertyExpression.Body is MemberExpression memberExpression)
|
||||
Member = memberExpression.Member;
|
||||
Getter = getter ?? throw new ArgumentNullException(nameof(getter));
|
||||
Setter = setter ?? throw new ArgumentNullException(nameof(setter));
|
||||
DisplayName = displayName ?? throw new ArgumentNullException(nameof(displayName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -32,15 +28,17 @@ namespace Artemis.Core
|
||||
public DataBindingConverter<TLayerProperty, TProperty> Converter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the expression that that accesses the property
|
||||
/// Gets the function to call to get the value of the property
|
||||
/// </summary>
|
||||
public Expression<Func<TLayerProperty, TProperty>> PropertyExpression { get; }
|
||||
public Func<TProperty> Getter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the member the <see cref="PropertyExpression" /> targets
|
||||
/// <para><see langword="null"/> if the <see cref="PropertyExpression" /> is not a member expression</para>
|
||||
/// Gets the action to call to set the value of the property
|
||||
/// </summary>
|
||||
public MemberInfo? Member { get; }
|
||||
public Action<TProperty> Setter { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DisplayName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data binding created using this registration
|
||||
@ -59,7 +57,7 @@ namespace Artemis.Core
|
||||
if (DataBinding != null)
|
||||
return DataBinding;
|
||||
|
||||
DataBindingEntity? dataBinding = LayerProperty.Entity.DataBindingEntities.FirstOrDefault(e => e.TargetExpression == PropertyExpression.ToString());
|
||||
DataBindingEntity? dataBinding = LayerProperty.Entity.DataBindingEntities.FirstOrDefault(e => e.Identifier == DisplayName);
|
||||
if (dataBinding == null)
|
||||
return null;
|
||||
|
||||
|
||||
@ -5,6 +5,11 @@
|
||||
/// </summary>
|
||||
public interface IDataBindingRegistration
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the display name of the data binding registration
|
||||
/// </summary>
|
||||
string DisplayName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the data binding applied using this registration
|
||||
/// </summary>
|
||||
|
||||
@ -97,6 +97,16 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs>? KeyframeRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a data binding property has been added
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingPropertyRegistered;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when all data binding properties have been removed
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingPropertiesCleared;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a data binding has been enabled
|
||||
/// </summary>
|
||||
|
||||
@ -379,21 +379,16 @@ namespace Artemis.Core
|
||||
public bool HasDataBinding => GetAllDataBindingRegistrations().Any(r => r.GetDataBinding() != null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a data binding registration by the expression used to register it
|
||||
/// Gets a data binding registration by the display name used to register it
|
||||
/// <para>Note: The expression must exactly match the one used to register the data binding</para>
|
||||
/// </summary>
|
||||
public DataBindingRegistration<T, TProperty>? GetDataBindingRegistration<TProperty>(Expression<Func<T, TProperty>> propertyExpression)
|
||||
{
|
||||
return GetDataBindingRegistration<TProperty>(propertyExpression.ToString());
|
||||
}
|
||||
|
||||
internal DataBindingRegistration<T, TProperty>? GetDataBindingRegistration<TProperty>(string expression)
|
||||
public DataBindingRegistration<T, TProperty>? GetDataBindingRegistration<TProperty>(string identifier)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("LayerProperty");
|
||||
|
||||
IDataBindingRegistration? match = _dataBindingRegistrations.FirstOrDefault(r => r is DataBindingRegistration<T, TProperty> registration &&
|
||||
registration.PropertyExpression.ToString() == expression);
|
||||
registration.DisplayName == identifier);
|
||||
return (DataBindingRegistration<T, TProperty>?) match;
|
||||
}
|
||||
|
||||
@ -410,21 +405,35 @@ namespace Artemis.Core
|
||||
/// Registers a data binding property so that is available to the data binding system
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty">The type of the layer property</typeparam>
|
||||
/// <param name="propertyExpression">The expression pointing to the value to register</param>
|
||||
/// <param name="getter">The function to call to get the value of the property</param>
|
||||
/// <param name="setter">The action to call to set the value of the property</param>
|
||||
/// <param name="converter">The converter to use while applying the data binding</param>
|
||||
public void RegisterDataBindingProperty<TProperty>(Expression<Func<T, TProperty>> propertyExpression, DataBindingConverter<T, TProperty> converter)
|
||||
/// <param name="displayName">The display name of the data binding property</param>
|
||||
public DataBindingRegistration<T, TProperty> RegisterDataBindingProperty<TProperty>(Func<TProperty> getter, Action<TProperty> setter, DataBindingConverter<T, TProperty> converter,
|
||||
string displayName)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("LayerProperty");
|
||||
if (_dataBindingRegistrations.Any(d => d.DisplayName == displayName))
|
||||
throw new ArtemisCoreException($"A databinding property named '{displayName}' is already registered.");
|
||||
|
||||
DataBindingRegistration<T, TProperty> registration = new(this, converter, getter, setter, displayName);
|
||||
_dataBindingRegistrations.Add(registration);
|
||||
|
||||
OnDataBindingPropertyRegistered();
|
||||
return registration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all data binding properties so they are no longer available to the data binding system
|
||||
/// </summary>
|
||||
public void ClearDataBindingProperties()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("LayerProperty");
|
||||
|
||||
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 != propertyExpression.ReturnType)
|
||||
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, propertyExpression));
|
||||
_dataBindingRegistrations.Clear();
|
||||
OnDataBindingPropertiesCleared();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -661,6 +670,12 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? KeyframeRemoved;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingPropertyRegistered;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingPropertiesCleared;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingEnabled;
|
||||
|
||||
@ -716,6 +731,22 @@ namespace Artemis.Core
|
||||
KeyframeRemoved?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DataBindingPropertyRegistered" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDataBindingPropertyRegistered()
|
||||
{
|
||||
DataBindingPropertyRegistered?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DataBindingDisabled" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDataBindingPropertiesCleared()
|
||||
{
|
||||
DataBindingPropertiesCleared?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DataBindingEnabled" /> event
|
||||
/// </summary>
|
||||
|
||||
@ -73,10 +73,10 @@ namespace Artemis.Core
|
||||
|
||||
if (!enable)
|
||||
{
|
||||
IsEnabled = false;
|
||||
|
||||
// Even if disable failed, still leave it in a disabled state to avoid more issues
|
||||
InternalDisable();
|
||||
IsEnabled = false;
|
||||
|
||||
OnDisabled();
|
||||
return;
|
||||
}
|
||||
@ -146,7 +146,7 @@ namespace Artemis.Core
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Disable();
|
||||
InternalDisable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ namespace Artemis.Storage.Entities.Profile.DataBindings
|
||||
{
|
||||
public class DataBindingEntity
|
||||
{
|
||||
public string TargetExpression { get; set; }
|
||||
public string Identifier { get; set; }
|
||||
public TimeSpan EasingTime { get; set; }
|
||||
public int EasingFunction { get; set; }
|
||||
|
||||
|
||||
55
src/Artemis.Storage/Migrations/M10BetterDataBindings.cs
Normal file
55
src/Artemis.Storage/Migrations/M10BetterDataBindings.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using Artemis.Storage.Migrations.Interfaces;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrations
|
||||
{
|
||||
public class M10BetterDataBindings : IStorageMigration
|
||||
{
|
||||
private void Migrate(BsonValue bsonValue)
|
||||
{
|
||||
if (!bsonValue.IsDocument || !bsonValue.AsDocument.TryGetValue("PropertyEntities", out BsonValue propertyEntities))
|
||||
return;
|
||||
|
||||
foreach (BsonValue propertyEntity in propertyEntities.AsArray)
|
||||
{
|
||||
if (!propertyEntity.AsDocument.TryGetValue("DataBindingEntities", out BsonValue dataBindingEntities))
|
||||
continue;
|
||||
foreach (BsonValue dataBindingEntity in dataBindingEntities.AsArray)
|
||||
{
|
||||
if (!dataBindingEntity.AsDocument.TryGetValue("TargetExpression", out BsonValue targetExpression))
|
||||
continue;
|
||||
string value = targetExpression.AsString;
|
||||
if (value == "value => value" || value == "b => b")
|
||||
{
|
||||
dataBindingEntity.AsDocument["Identifier"] = "Value";
|
||||
}
|
||||
else
|
||||
{
|
||||
string selector = value.Split("=>")[1];
|
||||
string property = selector.Split(".")[1];
|
||||
dataBindingEntity.AsDocument["Identifier"] = property;
|
||||
}
|
||||
|
||||
dataBindingEntity.AsDocument.Remove("TargetExpression");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int UserVersion => 10;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
||||
foreach (BsonDocument bsonDocument in collection.FindAll())
|
||||
{
|
||||
foreach (BsonValue bsonLayer in bsonDocument["Layers"].AsArray)
|
||||
Migrate(bsonLayer);
|
||||
|
||||
foreach (BsonValue bsonLayer in bsonDocument["Folders"].AsArray)
|
||||
Migrate(bsonLayer);
|
||||
|
||||
collection.Update(bsonDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.BoolPropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.BoolPropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
||||
@ -1,15 +1,25 @@
|
||||
using Artemis.Core;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class BoolPropertyInputViewModel : PropertyInputViewModel<bool>
|
||||
{
|
||||
private List<IDataBindingRegistration> _registrations;
|
||||
|
||||
public BoolPropertyInputViewModel(LayerProperty<bool> layerProperty, IProfileEditorService profileEditorService) : base(layerProperty, profileEditorService)
|
||||
{
|
||||
_registrations = layerProperty.GetAllDataBindingRegistrations();
|
||||
}
|
||||
|
||||
public bool IsEnabled => true;
|
||||
public bool IsEnabled => _registrations.Any(r => r.GetDataBinding() != null);
|
||||
|
||||
protected override void OnDataBindingsChanged()
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,12 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.BrushPropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.BrushPropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:propertyInput="clr-namespace:Artemis.UI.PropertyInput"
|
||||
xmlns:dataTemplateSelectors="clr-namespace:Artemis.UI.DataTemplateSelectors"
|
||||
xmlns:layerBrush="clr-namespace:Artemis.Core.LayerBrushes;assembly=Artemis.Core"
|
||||
xmlns:propertyInput="clr-namespace:Artemis.UI.DefaultTypes.PropertyInput"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type propertyInput:BrushPropertyInputViewModel}}">
|
||||
|
||||
@ -7,7 +7,7 @@ using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class BrushPropertyInputViewModel : PropertyInputViewModel<LayerBrushReference>
|
||||
{
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.ColorGradientPropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.ColorGradientPropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:propertyInput="clr-namespace:Artemis.UI.PropertyInput"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
|
||||
@ -3,7 +3,7 @@ using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class ColorGradientPropertyInputViewModel : PropertyInputViewModel<ColorGradient>
|
||||
{
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.EnumPropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.EnumPropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
||||
@ -4,7 +4,7 @@ using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class EnumPropertyInputViewModel<T> : PropertyInputViewModel<T> where T : Enum
|
||||
{
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.FloatPropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.FloatPropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
xmlns:propertyInput="clr-namespace:Artemis.UI.PropertyInput"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
|
||||
@ -4,7 +4,7 @@ using Artemis.UI.Shared.Services;
|
||||
using FluentValidation;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class FloatPropertyInputViewModel : PropertyInputViewModel<float>
|
||||
{
|
||||
@ -13,7 +13,7 @@ namespace Artemis.UI.PropertyInput
|
||||
public FloatPropertyInputViewModel(LayerProperty<float> layerProperty, IProfileEditorService profileEditorService, IModelValidator<FloatPropertyInputViewModel> validator)
|
||||
: base(layerProperty, profileEditorService, validator)
|
||||
{
|
||||
_registration = layerProperty.GetDataBindingRegistration(value => value);
|
||||
_registration = layerProperty.GetDataBindingRegistration<float>("Value");
|
||||
}
|
||||
|
||||
public bool IsEnabled => _registration.DataBinding == null;
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.FloatRangePropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.FloatRangePropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.PropertyInput"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
|
||||
@ -5,7 +5,7 @@ using Artemis.UI.Shared.Services;
|
||||
using FluentValidation;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class FloatRangePropertyInputViewModel : PropertyInputViewModel<FloatRange>
|
||||
{
|
||||
@ -16,8 +16,8 @@ namespace Artemis.UI.PropertyInput
|
||||
IProfileEditorService profileEditorService,
|
||||
IModelValidator<FloatRangePropertyInputViewModel> validator) : base(layerProperty, profileEditorService, validator)
|
||||
{
|
||||
_startRegistration = layerProperty.GetDataBindingRegistration(range => range.Start);
|
||||
_endRegistration = layerProperty.GetDataBindingRegistration(range => range.End);
|
||||
_startRegistration = layerProperty.GetDataBindingRegistration<float>("Start");
|
||||
_endRegistration = layerProperty.GetDataBindingRegistration<float>("End");
|
||||
}
|
||||
|
||||
public float Start
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.IntPropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.IntPropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
xmlns:propertyInput="clr-namespace:Artemis.UI.PropertyInput"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
|
||||
@ -4,7 +4,7 @@ using Artemis.UI.Shared.Services;
|
||||
using FluentValidation;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class IntPropertyInputViewModel : PropertyInputViewModel<int>
|
||||
{
|
||||
@ -13,7 +13,7 @@ namespace Artemis.UI.PropertyInput
|
||||
public IntPropertyInputViewModel(LayerProperty<int> layerProperty, IProfileEditorService profileEditorService, IModelValidator<IntPropertyInputViewModel> validator)
|
||||
: base(layerProperty, profileEditorService, validator)
|
||||
{
|
||||
_registration = layerProperty.GetDataBindingRegistration(value => value);
|
||||
_registration = layerProperty.GetDataBindingRegistration<int>("Value");
|
||||
}
|
||||
|
||||
public bool IsEnabled => _registration.DataBinding == null;
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.IntRangePropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.IntRangePropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.PropertyInput"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
|
||||
@ -5,7 +5,7 @@ using Artemis.UI.Shared.Services;
|
||||
using FluentValidation;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class IntRangePropertyInputViewModel : PropertyInputViewModel<IntRange>
|
||||
{
|
||||
@ -16,8 +16,8 @@ namespace Artemis.UI.PropertyInput
|
||||
IProfileEditorService profileEditorService,
|
||||
IModelValidator<IntRangePropertyInputViewModel> validator) : base(layerProperty, profileEditorService, validator)
|
||||
{
|
||||
_startRegistration = layerProperty.GetDataBindingRegistration(range => range.Start);
|
||||
_endRegistration = layerProperty.GetDataBindingRegistration(range => range.End);
|
||||
_startRegistration = layerProperty.GetDataBindingRegistration<int>("Start");
|
||||
_endRegistration = layerProperty.GetDataBindingRegistration<int>("End");
|
||||
}
|
||||
|
||||
public int Start
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.SKColorPropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.SKColorPropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:artemis="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
xmlns:propertyInput="clr-namespace:Artemis.UI.PropertyInput"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="25" d:DesignWidth="800"
|
||||
|
||||
@ -3,7 +3,7 @@ using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class SKColorPropertyInputViewModel : PropertyInputViewModel<SKColor>
|
||||
{
|
||||
@ -11,7 +11,7 @@ namespace Artemis.UI.PropertyInput
|
||||
|
||||
public SKColorPropertyInputViewModel(LayerProperty<SKColor> layerProperty, IProfileEditorService profileEditorService) : base(layerProperty, profileEditorService)
|
||||
{
|
||||
_registration = layerProperty.GetDataBindingRegistration(value => value);
|
||||
_registration = layerProperty.GetDataBindingRegistration<SKColor>("Value");
|
||||
}
|
||||
|
||||
public bool IsEnabled => _registration.DataBinding == null;
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.SKPointPropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.SKPointPropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
xmlns:propertyInput="clr-namespace:Artemis.UI.PropertyInput"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="25" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance propertyInput:SKPointPropertyInputViewModel}">
|
||||
|
||||
@ -6,7 +6,7 @@ using FluentValidation;
|
||||
using SkiaSharp;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class SKPointPropertyInputViewModel : PropertyInputViewModel<SKPoint>
|
||||
{
|
||||
@ -16,8 +16,8 @@ namespace Artemis.UI.PropertyInput
|
||||
public SKPointPropertyInputViewModel(LayerProperty<SKPoint> layerProperty, IProfileEditorService profileEditorService,
|
||||
IModelValidator<SKPointPropertyInputViewModel> validator) : base(layerProperty, profileEditorService, validator)
|
||||
{
|
||||
_xRegistration = layerProperty.GetDataBindingRegistration(point => point.X);
|
||||
_yRegistration = layerProperty.GetDataBindingRegistration(point => point.Y);
|
||||
_xRegistration = layerProperty.GetDataBindingRegistration<float>("X");
|
||||
_yRegistration = layerProperty.GetDataBindingRegistration<float>("Y");
|
||||
}
|
||||
|
||||
public float X
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
<UserControl x:Class="Artemis.UI.PropertyInput.SKSizePropertyInputView"
|
||||
<UserControl x:Class="Artemis.UI.DefaultTypes.PropertyInput.SKSizePropertyInputView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.PropertyInput"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
|
||||
@ -8,7 +8,7 @@ using Stylet;
|
||||
|
||||
// using PropertyChanged;
|
||||
|
||||
namespace Artemis.UI.PropertyInput
|
||||
namespace Artemis.UI.DefaultTypes.PropertyInput
|
||||
{
|
||||
public class SKSizePropertyInputViewModel : PropertyInputViewModel<SKSize>
|
||||
{
|
||||
@ -18,8 +18,8 @@ namespace Artemis.UI.PropertyInput
|
||||
public SKSizePropertyInputViewModel(LayerProperty<SKSize> layerProperty, IProfileEditorService profileEditorService,
|
||||
IModelValidator<SKSizePropertyInputViewModel> validator) : base(layerProperty, profileEditorService, validator)
|
||||
{
|
||||
_widthRegistration = layerProperty.GetDataBindingRegistration(size => size.Width);
|
||||
_heightRegistration = layerProperty.GetDataBindingRegistration(size => size.Height);
|
||||
_widthRegistration = layerProperty.GetDataBindingRegistration<float>("Width");
|
||||
_heightRegistration = layerProperty.GetDataBindingRegistration<float>("Height");
|
||||
}
|
||||
|
||||
// Since SKSize is immutable we need to create properties that replace the SKSize entirely
|
||||
|
||||
@ -38,11 +38,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataBindingsVmFactory = dataBindingsVmFactory;
|
||||
|
||||
if (Registration.Member != null)
|
||||
DisplayName = Registration.Member.Name.ToUpper();
|
||||
else
|
||||
DisplayName = Registration.LayerProperty.PropertyDescription.Name.ToUpper();
|
||||
|
||||
DisplayName = Registration.DisplayName.ToUpper();
|
||||
AlwaysApplyDataBindings = settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", true);
|
||||
DataBindingModes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(DataBindingModeType)));
|
||||
EasingViewModels = new BindableCollection<TimelineEasingViewModel>();
|
||||
@ -106,8 +102,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
base.OnInitialActivate();
|
||||
Initialize();
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
|
||||
@ -6,11 +6,18 @@
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<TabControl ItemsSource="{Binding Items}" SelectedIndex="{Binding SelectedItemIndex}" DisplayMemberPath="DisplayName" Style="{StaticResource MaterialDesignTabControl}">
|
||||
<TabControl ItemsSource="{Binding Items}"
|
||||
SelectedIndex="{Binding SelectedItemIndex}"
|
||||
Style="{StaticResource MaterialDesignTabControl}" >
|
||||
<TabControl.ContentTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" TextElement.Foreground="{DynamicResource MaterialDesignBody}" />
|
||||
</DataTemplate>
|
||||
</TabControl.ContentTemplate>
|
||||
<TabControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Margin="-12 0" Text="{Binding DisplayName}"></TextBlock>
|
||||
</DataTemplate>
|
||||
</TabControl.ItemTemplate>
|
||||
</TabControl>
|
||||
</UserControl>
|
||||
@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Services;
|
||||
@ -11,7 +14,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
{
|
||||
private readonly IDataBindingsVmFactory _dataBindingsVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private ILayerProperty? _selectedDataBinding;
|
||||
private int _selectedItemIndex;
|
||||
private bool _updating;
|
||||
|
||||
public DataBindingsViewModel(IProfileEditorService profileEditorService, IDataBindingsVmFactory dataBindingsVmFactory)
|
||||
{
|
||||
@ -24,9 +29,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
get => _selectedItemIndex;
|
||||
set => SetAndNotify(ref _selectedItemIndex, value);
|
||||
}
|
||||
|
||||
|
||||
private void CreateDataBindingViewModels()
|
||||
{
|
||||
int oldIndex = SelectedItemIndex;
|
||||
Items.Clear();
|
||||
|
||||
ILayerProperty layerProperty = _profileEditorService.SelectedDataBinding;
|
||||
@ -37,26 +43,64 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
|
||||
// Create a data binding VM for each data bindable property. These VMs will be responsible for retrieving
|
||||
// and creating the actual data bindings
|
||||
foreach (IDataBindingRegistration registration in registrations)
|
||||
Items.Add(_dataBindingsVmFactory.DataBindingViewModel(registration));
|
||||
Items.AddRange(registrations.Select(registration => _dataBindingsVmFactory.DataBindingViewModel(registration)));
|
||||
|
||||
SelectedItemIndex = 0;
|
||||
SelectedItemIndex = Items.Count < oldIndex ? 0 : oldIndex;
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnSelectedDataBindingChanged(object sender, EventArgs e)
|
||||
{
|
||||
CreateDataBindingViewModels();
|
||||
SubscribeToSelectedDataBinding();
|
||||
|
||||
SelectedItemIndex = 0;
|
||||
}
|
||||
|
||||
private void SubscribeToSelectedDataBinding()
|
||||
{
|
||||
if (_selectedDataBinding != null)
|
||||
{
|
||||
_selectedDataBinding.DataBindingPropertyRegistered -= DataBindingRegistrationsChanged;
|
||||
_selectedDataBinding.DataBindingPropertiesCleared -= DataBindingRegistrationsChanged;
|
||||
}
|
||||
|
||||
_selectedDataBinding = _profileEditorService.SelectedDataBinding;
|
||||
if (_selectedDataBinding != null)
|
||||
{
|
||||
_selectedDataBinding.DataBindingPropertyRegistered += DataBindingRegistrationsChanged;
|
||||
_selectedDataBinding.DataBindingPropertiesCleared += DataBindingRegistrationsChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void DataBindingRegistrationsChanged(object sender, LayerPropertyEventArgs e)
|
||||
{
|
||||
if (_updating)
|
||||
return;
|
||||
|
||||
_updating = true;
|
||||
Execute.PostToUIThread(async () =>
|
||||
{
|
||||
await Task.Delay(200);
|
||||
CreateDataBindingViewModels();
|
||||
_updating = false;
|
||||
});
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
_profileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged;
|
||||
CreateDataBindingViewModels();
|
||||
SubscribeToSelectedDataBinding();
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
protected override void OnActivate()
|
||||
{
|
||||
SelectedItemIndex = 0;
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
|
||||
@ -302,7 +302,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
TimeSpan delta = DateTime.Now - _lastUpdate;
|
||||
_lastUpdate = DateTime.Now;
|
||||
|
||||
if (!AlwaysApplyDataBindings.Value || _profileEditorService.SelectedProfile == null || _profileEditorService.Playing)
|
||||
if (!AlwaysApplyDataBindings.Value || _profileEditorService.SelectedProfile == null)
|
||||
return;
|
||||
|
||||
foreach (IDataBindingRegistration dataBindingRegistration in _profileEditorService.SelectedProfile.GetAllFolders()
|
||||
|
||||
@ -4,9 +4,9 @@ using Artemis.Core.Services;
|
||||
using Artemis.UI.Controllers;
|
||||
using Artemis.UI.DefaultTypes.DataModel.Display;
|
||||
using Artemis.UI.DefaultTypes.DataModel.Input;
|
||||
using Artemis.UI.DefaultTypes.PropertyInput;
|
||||
using Artemis.UI.InputProviders;
|
||||
using Artemis.UI.Ninject;
|
||||
using Artemis.UI.PropertyInput;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Serilog;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user