mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Data bindings - Rewrote data binding system to fully leverage nodes
This commit is contained in:
1 parent
7933bf7ee9
commit
0bb93f2ebd
63 files changed
+654
-1533
No files matched your search
@@ -84,4 +84,8 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="DefaultTypes\DataBindings\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,47 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class FloatDataBindingConverter : FloatDataBindingConverter<float>
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <typeparam name="T">The type of layer property this converter is applied to</typeparam>
|
||||
public class FloatDataBindingConverter<T> : DataBindingConverter<T, float>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="FloatDataBindingConverter{T}" /> class
|
||||
/// </summary>
|
||||
public FloatDataBindingConverter()
|
||||
{
|
||||
SupportsSum = true;
|
||||
SupportsInterpolate = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override float Sum(float a, float b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override float Interpolate(float a, float b, double progress)
|
||||
{
|
||||
float diff = b - a;
|
||||
return (float) (a + diff * progress);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ApplyValue(float value)
|
||||
{
|
||||
if (DataBinding!.LayerProperty.PropertyDescription.MaxInputValue is float max)
|
||||
value = Math.Min(value, max);
|
||||
if (DataBinding!.LayerProperty.PropertyDescription.MinInputValue is float min)
|
||||
value = Math.Max(value, min);
|
||||
|
||||
base.ApplyValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic data binding converter that acts as the bridge between a
|
||||
/// <see cref="DataBinding{TLayerProperty, TProperty}" /> and a <see cref="LayerProperty{T}" /> and does not support
|
||||
/// sum or interpolation
|
||||
/// </summary>
|
||||
public class GeneralDataBindingConverter<T> : DataBindingConverter<T, T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="GeneralDataBindingConverter{T}" /> class
|
||||
/// </summary>
|
||||
public GeneralDataBindingConverter()
|
||||
{
|
||||
SupportsSum = false;
|
||||
SupportsInterpolate = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override T Sum(T a, T b)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override T Interpolate(T a, T b, double progress)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class IntDataBindingConverter : IntDataBindingConverter<int>
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public class IntDataBindingConverter<T> : DataBindingConverter<T, int>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="IntDataBindingConverter{T}" /> class
|
||||
/// </summary>
|
||||
public IntDataBindingConverter()
|
||||
{
|
||||
SupportsSum = true;
|
||||
SupportsInterpolate = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="MidpointRounding" /> mode used for rounding during interpolation. Defaults to
|
||||
/// <see cref="MidpointRounding.AwayFromZero" />
|
||||
/// </summary>
|
||||
public MidpointRounding InterpolationRoundingMode { get; set; } = MidpointRounding.AwayFromZero;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int Sum(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int Interpolate(int a, int b, double progress)
|
||||
{
|
||||
int diff = b - a;
|
||||
return (int) Math.Round(a + diff * progress, InterpolationRoundingMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class SKColorDataBindingConverter : DataBindingConverter<SKColor, SKColor>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="SKColorDataBindingConverter" /> class
|
||||
/// </summary>
|
||||
public SKColorDataBindingConverter()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,14 @@
|
||||
public class BoolLayerProperty : LayerProperty<bool>
|
||||
{
|
||||
internal BoolLayerProperty()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
KeyframesSupported = false;
|
||||
RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, new GeneralDataBindingConverter<bool>(), "Value");
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, "Value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace Artemis.Core
|
||||
internal ColorGradientLayerProperty()
|
||||
{
|
||||
KeyframesSupported = false;
|
||||
DataBindingsSupported = true;
|
||||
DefaultValue = new ColorGradient();
|
||||
|
||||
CurrentValueSet += OnCurrentValueSet;
|
||||
@@ -20,7 +19,7 @@ namespace Artemis.Core
|
||||
|
||||
private void CreateDataBindingRegistrations()
|
||||
{
|
||||
ClearDataBindingProperties();
|
||||
DataBinding.ClearDataBindingProperties();
|
||||
if (CurrentValue == null)
|
||||
return;
|
||||
|
||||
@@ -33,7 +32,7 @@ namespace Artemis.Core
|
||||
CurrentValue[stopIndex].Color = value;
|
||||
}
|
||||
|
||||
RegisterDataBindingProperty(() => CurrentValue[stopIndex].Color, Setter, new ColorStopDataBindingConverter(), $"Color #{stopIndex + 1}");
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue[stopIndex].Color, Setter, $"Color #{stopIndex + 1}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +70,7 @@ namespace Artemis.Core
|
||||
|
||||
private void SubscribedGradientOnPropertyChanged(object? sender, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
if (CurrentValue.Count != GetAllDataBindingRegistrations().Count)
|
||||
if (CurrentValue.Count != DataBinding.Properties.Count)
|
||||
CreateDataBindingRegistrations();
|
||||
}
|
||||
|
||||
@@ -89,25 +88,4 @@ namespace Artemis.Core
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ namespace Artemis.Core
|
||||
internal EnumLayerProperty()
|
||||
{
|
||||
KeyframesSupported = false;
|
||||
DataBindingsSupported = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,7 +5,12 @@
|
||||
{
|
||||
internal FloatLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, new FloatDataBindingConverter(), "Value");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, "Value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,13 +5,17 @@
|
||||
{
|
||||
internal FloatRangeLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(() => CurrentValue.Start, value => CurrentValue.Start = value, new FloatDataBindingConverter<FloatRange>(), "Start");
|
||||
RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue.End = value, new FloatDataBindingConverter<FloatRange>(), "End");
|
||||
|
||||
CurrentValueSet += OnCurrentValueSet;
|
||||
DefaultValue = new FloatRange();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue.Start, value => CurrentValue.Start = value, "Start");
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue.End = value, "End");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,12 @@ namespace Artemis.Core
|
||||
{
|
||||
internal IntLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, new IntDataBindingConverter(), "Value");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, "Value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,13 +5,17 @@
|
||||
{
|
||||
internal IntRangeLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(() => CurrentValue.Start, value => CurrentValue.Start = value, new IntDataBindingConverter<IntRange>(), "Start");
|
||||
RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue.End = value, new IntDataBindingConverter<IntRange>(), "End");
|
||||
|
||||
CurrentValueSet += OnCurrentValueSet;
|
||||
DefaultValue = new IntRange();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue.Start, value => CurrentValue.Start = value, "Start");
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue.End = value, "End");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
internal LayerBrushReferenceLayerProperty()
|
||||
{
|
||||
KeyframesSupported = false;
|
||||
DataBindingsSupported = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,7 +7,12 @@ namespace Artemis.Core
|
||||
{
|
||||
internal SKColorLayerProperty()
|
||||
{
|
||||
RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, new SKColorDataBindingConverter(), "Value");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue, value => CurrentValue = value, "Value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,8 +7,13 @@ namespace Artemis.Core
|
||||
{
|
||||
internal SKPointLayerProperty()
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue.X, value => CurrentValue = new SKPoint(value, CurrentValue.Y), "X");
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue.Y, value => CurrentValue = new SKPoint(CurrentValue.X, value), "Y");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,8 +7,13 @@ namespace Artemis.Core
|
||||
{
|
||||
internal SKSizeLayerProperty()
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue.Width, (value) => CurrentValue = new SKSize(value, CurrentValue.Height), "Width");
|
||||
DataBinding.RegisterDataBindingProperty(() => CurrentValue.Height, (value) => CurrentValue = new SKSize(CurrentValue.Width, value), "Height");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides data for data binding events.
|
||||
/// </summary>
|
||||
public class DataBindingEventArgs : EventArgs
|
||||
{
|
||||
internal DataBindingEventArgs(IDataBinding dataBinding)
|
||||
{
|
||||
DataBinding = dataBinding;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data binding this event is related to
|
||||
/// </summary>
|
||||
public IDataBinding DataBinding { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.Storage.Entities.Profile.DataBindings;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class DataBinding<TLayerProperty, TProperty> : IDataBinding
|
||||
public class DataBinding<TLayerProperty> : IDataBinding
|
||||
{
|
||||
private TProperty _currentValue = default!;
|
||||
private readonly List<IDataBindingProperty> _properties = new();
|
||||
private bool _disposed;
|
||||
private TimeSpan _easingProgress;
|
||||
private TProperty _lastAppliedValue = default!;
|
||||
private TProperty _previousValue = default!;
|
||||
private bool _reapplyValue;
|
||||
private bool _isEnabled;
|
||||
|
||||
internal DataBinding(DataBindingRegistration<TLayerProperty, TProperty> dataBindingRegistration)
|
||||
internal DataBinding(LayerProperty<TLayerProperty> layerProperty)
|
||||
{
|
||||
LayerProperty = dataBindingRegistration.LayerProperty;
|
||||
Entity = new DataBindingEntity();
|
||||
LayerProperty = layerProperty;
|
||||
|
||||
ApplyRegistration(dataBindingRegistration);
|
||||
Script = new NodeScript<TProperty>(GetScriptName(), "The value to put into the data binding", LayerProperty.ProfileElement.Profile);
|
||||
Entity = new DataBindingEntity();
|
||||
Script = new DataBindingNodeScript<TLayerProperty>(GetScriptName(), "The value to put into the data binding", this, LayerProperty.ProfileElement.Profile);
|
||||
|
||||
Save();
|
||||
}
|
||||
@@ -27,39 +26,23 @@ namespace Artemis.Core
|
||||
internal DataBinding(LayerProperty<TLayerProperty> layerProperty, DataBindingEntity entity)
|
||||
{
|
||||
LayerProperty = layerProperty;
|
||||
|
||||
Entity = entity;
|
||||
Script = new NodeScript<TProperty>(GetScriptName(), "The value to put into the data binding", LayerProperty.ProfileElement.Profile);
|
||||
Script = new DataBindingNodeScript<TLayerProperty>(GetScriptName(), "The value to put into the data binding", this, LayerProperty.ProfileElement.Profile);
|
||||
|
||||
// Load will add children so be initialized before that
|
||||
Load();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data binding registration this data binding is based upon
|
||||
/// </summary>
|
||||
public DataBindingRegistration<TLayerProperty, TProperty>? Registration { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layer property this data binding targets
|
||||
/// </summary>
|
||||
public LayerProperty<TLayerProperty> LayerProperty { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the converter used to apply this data binding to the <see cref="LayerProperty" />
|
||||
/// Gets the script used to populate the data binding
|
||||
/// </summary>
|
||||
public DataBindingConverter<TLayerProperty, TProperty>? Converter { get; private set; }
|
||||
|
||||
public NodeScript<TProperty> Script { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the easing time of the data binding
|
||||
/// </summary>
|
||||
public TimeSpan EasingTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets ors ets the easing function of the data binding
|
||||
/// </summary>
|
||||
public Easings.Functions EasingFunction { get; set; }
|
||||
public DataBindingNodeScript<TLayerProperty> Script { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data binding entity this data binding uses for persistent storage
|
||||
@@ -67,38 +50,52 @@ namespace Artemis.Core
|
||||
public DataBindingEntity Entity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value of the data binding
|
||||
/// Updates the pending values of this data binding
|
||||
/// </summary>
|
||||
/// <param name="baseValue">The base value of the property the data binding is applied to</param>
|
||||
/// <returns></returns>
|
||||
public TProperty GetValue(TProperty baseValue)
|
||||
public void Update()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("DataBinding");
|
||||
|
||||
if (Converter == null)
|
||||
return baseValue;
|
||||
if (!IsEnabled)
|
||||
return;
|
||||
|
||||
// TODO: Update the base node
|
||||
|
||||
Script.Run();
|
||||
|
||||
// If no easing is to be applied simple return whatever the current value is
|
||||
if (EasingTime == TimeSpan.Zero || !Converter.SupportsInterpolate)
|
||||
return Script.Result;
|
||||
|
||||
// If the value changed, update the current and previous values used for easing
|
||||
if (!Equals(Script.Result, _currentValue))
|
||||
ResetEasing(Script.Result);
|
||||
|
||||
// Apply interpolation between the previous and current value
|
||||
return GetInterpolatedValue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the type of the target property of this data binding
|
||||
/// Registers a data binding property so that is available to the data binding system
|
||||
/// </summary>
|
||||
public Type? GetTargetType()
|
||||
/// <typeparam name="TProperty">The type of the layer property</typeparam>
|
||||
/// <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="displayName">The display name of the data binding property</param>
|
||||
public DataBindingProperty<TProperty> RegisterDataBindingProperty<TProperty>(Func<TProperty> getter, Action<TProperty?> setter, string displayName)
|
||||
{
|
||||
return Registration?.Getter.Method.ReturnType;
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("DataBinding");
|
||||
if (Properties.Any(d => d.DisplayName == displayName))
|
||||
throw new ArtemisCoreException($"A databinding property named '{displayName}' is already registered.");
|
||||
|
||||
DataBindingProperty<TProperty> property = new(getter, setter, displayName);
|
||||
_properties.Add(property);
|
||||
|
||||
OnDataBindingPropertyRegistered();
|
||||
return property;
|
||||
}
|
||||
|
||||
/// <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");
|
||||
|
||||
_properties.Clear();
|
||||
OnDataBindingPropertiesCleared();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -113,111 +110,78 @@ namespace Artemis.Core
|
||||
if (disposing)
|
||||
{
|
||||
_disposed = true;
|
||||
|
||||
if (Registration != null)
|
||||
Registration.DataBinding = null;
|
||||
|
||||
Script.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetEasing(TProperty value)
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DataBindingPropertyRegistered" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDataBindingPropertyRegistered()
|
||||
{
|
||||
_previousValue = GetInterpolatedValue();
|
||||
_currentValue = value;
|
||||
_easingProgress = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
private void ApplyRegistration(DataBindingRegistration<TLayerProperty, TProperty> dataBindingRegistration)
|
||||
{
|
||||
if (dataBindingRegistration == null)
|
||||
throw new ArgumentNullException(nameof(dataBindingRegistration));
|
||||
|
||||
dataBindingRegistration.DataBinding = this;
|
||||
Converter = dataBindingRegistration.Converter;
|
||||
Registration = dataBindingRegistration;
|
||||
|
||||
if (GetTargetType()!.IsValueType)
|
||||
{
|
||||
if (_currentValue == null)
|
||||
_currentValue = default!;
|
||||
if (_previousValue == null)
|
||||
_previousValue = default!;
|
||||
}
|
||||
|
||||
Converter?.Initialize(this);
|
||||
}
|
||||
|
||||
private TProperty GetInterpolatedValue()
|
||||
{
|
||||
if (_easingProgress == EasingTime || Converter == null || !Converter.SupportsInterpolate)
|
||||
return _currentValue;
|
||||
|
||||
double easingAmount = _easingProgress.TotalSeconds / EasingTime.TotalSeconds;
|
||||
return Converter.Interpolate(_previousValue, _currentValue, Easings.Interpolate(easingAmount, EasingFunction));
|
||||
DataBindingPropertyRegistered?.Invoke(this, new DataBindingEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the smoothing progress of the data binding
|
||||
/// Invokes the <see cref="DataBindingDisabled" /> event
|
||||
/// </summary>
|
||||
/// <param name="timeline">The timeline to apply during update</param>
|
||||
public void Update(Timeline timeline)
|
||||
protected virtual void OnDataBindingPropertiesCleared()
|
||||
{
|
||||
// Don't update data bindings if there is no delta, otherwise this creates an inconsistency between
|
||||
// data bindings with easing and data bindings without easing (the ones with easing will seemingly not update)
|
||||
if (timeline.Delta == TimeSpan.Zero || timeline.IsOverridden)
|
||||
return;
|
||||
DataBindingPropertiesCleared?.Invoke(this, new DataBindingEventArgs(this));
|
||||
}
|
||||
|
||||
UpdateWithDelta(timeline.Delta);
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DataBindingEnabled" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDataBindingEnabled(DataBindingEventArgs e)
|
||||
{
|
||||
DataBindingEnabled?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DataBindingDisabled" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDataBindingDisabled(DataBindingEventArgs e)
|
||||
{
|
||||
DataBindingDisabled?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private string GetScriptName()
|
||||
{
|
||||
return LayerProperty.PropertyDescription.Name ?? LayerProperty.Path;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void UpdateWithDelta(TimeSpan delta)
|
||||
public ILayerProperty BaseLayerProperty => LayerProperty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsEnabled
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("DataBinding");
|
||||
get => _isEnabled;
|
||||
set
|
||||
{
|
||||
_isEnabled = value;
|
||||
|
||||
// Data bindings cannot go back in time like brushes
|
||||
if (delta < TimeSpan.Zero)
|
||||
delta = TimeSpan.Zero;
|
||||
|
||||
_easingProgress = _easingProgress.Add(delta);
|
||||
if (_easingProgress > EasingTime)
|
||||
_easingProgress = EasingTime;
|
||||
|
||||
// Tell Apply() to apply a new value next call
|
||||
_reapplyValue = false;
|
||||
if (_isEnabled)
|
||||
OnDataBindingEnabled(new DataBindingEventArgs(this));
|
||||
else
|
||||
OnDataBindingDisabled(new DataBindingEventArgs(this));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyCollection<IDataBindingProperty> Properties => _properties.AsReadOnly();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Apply()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("DataBinding");
|
||||
|
||||
if (Converter == null)
|
||||
if (!IsEnabled)
|
||||
return;
|
||||
|
||||
// If Update() has not been called, reapply the previous value
|
||||
if (_reapplyValue)
|
||||
{
|
||||
Converter.ApplyValue(_lastAppliedValue);
|
||||
return;
|
||||
}
|
||||
|
||||
TProperty converterValue = Converter.GetValue();
|
||||
TProperty value = GetValue(converterValue);
|
||||
Converter.ApplyValue(value);
|
||||
|
||||
_lastAppliedValue = value;
|
||||
_reapplyValue = true;
|
||||
}
|
||||
|
||||
private string GetScriptName()
|
||||
{
|
||||
if (LayerProperty.GetAllDataBindingRegistrations().Count == 1)
|
||||
return LayerProperty.PropertyDescription.Name ?? LayerProperty.Path;
|
||||
return $"{LayerProperty.PropertyDescription.Name ?? LayerProperty.Path} - {Registration?.DisplayName}";
|
||||
Script.DataBindingExitNode.ApplyToDataBinding();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -227,6 +191,19 @@ namespace Artemis.Core
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<DataBindingEventArgs>? DataBindingPropertyRegistered;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<DataBindingEventArgs>? DataBindingPropertiesCleared;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<DataBindingEventArgs>? DataBindingEnabled;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<DataBindingEventArgs>? DataBindingDisabled;
|
||||
|
||||
|
||||
#region Storage
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -234,14 +211,6 @@ namespace Artemis.Core
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("DataBinding");
|
||||
|
||||
// General
|
||||
DataBindingRegistration<TLayerProperty, TProperty>? registration = LayerProperty.GetDataBindingRegistration<TProperty>(Entity.Identifier);
|
||||
if (registration != null)
|
||||
ApplyRegistration(registration);
|
||||
|
||||
EasingTime = Entity.EasingTime;
|
||||
EasingFunction = (Easings.Functions) Entity.EasingFunction;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -249,8 +218,8 @@ namespace Artemis.Core
|
||||
{
|
||||
Script.Dispose();
|
||||
Script = Entity.NodeScript != null
|
||||
? new NodeScript<TProperty>(GetScriptName(), "The value to put into the data binding", Entity.NodeScript, LayerProperty.ProfileElement.Profile)
|
||||
: new NodeScript<TProperty>(GetScriptName(), "The value to put into the data binding", LayerProperty.ProfileElement.Profile);
|
||||
? new DataBindingNodeScript<TLayerProperty>(GetScriptName(), "The value to put into the data binding", this, Entity.NodeScript, LayerProperty.ProfileElement.Profile)
|
||||
: new DataBindingNodeScript<TLayerProperty>(GetScriptName(), "The value to put into the data binding", this, LayerProperty.ProfileElement.Profile);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -259,17 +228,7 @@ namespace Artemis.Core
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("DataBinding");
|
||||
|
||||
if (!LayerProperty.Entity.DataBindingEntities.Contains(Entity))
|
||||
LayerProperty.Entity.DataBindingEntities.Add(Entity);
|
||||
|
||||
// Don't save an invalid state
|
||||
if (Registration != null)
|
||||
Entity.Identifier = Registration.DisplayName;
|
||||
|
||||
Entity.EasingTime = EasingTime;
|
||||
Entity.EasingFunction = (int) EasingFunction;
|
||||
|
||||
Script?.Save();
|
||||
Script.Save();
|
||||
Entity.NodeScript = Script?.Entity;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a data binding converter that acts as the bridge between a
|
||||
/// <see cref="DataBinding{TLayerProperty, TProperty}" /> and a <see cref="LayerProperty{T}" />
|
||||
/// </summary>
|
||||
public abstract class DataBindingConverter<TLayerProperty, TProperty> : IDataBindingConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the data binding this converter is applied to
|
||||
/// </summary>
|
||||
public DataBinding<TLayerProperty, TProperty>? DataBinding { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not this data binding converter supports the <see cref="Sum" /> method
|
||||
/// </summary>
|
||||
public bool SupportsSum { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not this data binding converter supports the <see cref="Interpolate" /> method
|
||||
/// </summary>
|
||||
public bool SupportsInterpolate { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the sum of <paramref name="a" /> and <paramref name="b" />
|
||||
/// </summary>
|
||||
public abstract TProperty Sum(TProperty a, TProperty b);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the the interpolated value between <paramref name="a" /> and <paramref name="b" /> on a scale (generally)
|
||||
/// between <c>0.0</c> and <c>1.0</c> defined by the <paramref name="progress" />
|
||||
/// <para>Note: The progress may go be negative or go beyond <c>1.0</c> depending on the easing method used</para>
|
||||
/// </summary>
|
||||
/// <param name="a">The value to interpolate away from</param>
|
||||
/// <param name="b">The value to interpolate towards</param>
|
||||
/// <param name="progress">The progress of the interpolation between 0.0 and 1.0</param>
|
||||
/// <returns></returns>
|
||||
public abstract TProperty Interpolate(TProperty a, TProperty b, double progress);
|
||||
|
||||
/// <summary>
|
||||
/// Applies the <paramref name="value" /> to the layer property
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public virtual void ApplyValue(TProperty value)
|
||||
{
|
||||
if (DataBinding?.Registration == null)
|
||||
throw new ArtemisCoreException("Data binding converter is not yet initialized");
|
||||
DataBinding.Registration.Setter(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current base value of the data binding
|
||||
/// </summary>
|
||||
public virtual TProperty GetValue()
|
||||
{
|
||||
if (DataBinding?.Registration == null)
|
||||
throw new ArtemisCoreException("Data binding converter is not yet initialized");
|
||||
return DataBinding.Registration.Getter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the provided object to a type of <typeparamref name="TProperty" />
|
||||
/// </summary>
|
||||
public virtual TProperty ConvertFromObject(object? source)
|
||||
{
|
||||
return (TProperty) Convert.ChangeType(source, typeof(TProperty))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the data binding converter has been initialized and the <see cref="DataBinding" /> is available
|
||||
/// </summary>
|
||||
protected virtual void OnInitialized()
|
||||
{
|
||||
}
|
||||
|
||||
internal void Initialize(DataBinding<TLayerProperty, TProperty> dataBinding)
|
||||
{
|
||||
if (dataBinding.Registration == null)
|
||||
throw new ArtemisCoreException("Cannot initialize a data binding converter for a data binding without a registration");
|
||||
|
||||
DataBinding = dataBinding;
|
||||
OnInitialized();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Type SupportedType => typeof(TProperty);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class DataBindingProperty<TProperty> : IDataBindingProperty
|
||||
{
|
||||
internal DataBindingProperty(Func<TProperty> getter, Action<TProperty?> setter, string displayName)
|
||||
{
|
||||
Getter = getter ?? throw new ArgumentNullException(nameof(getter));
|
||||
Setter = setter ?? throw new ArgumentNullException(nameof(setter));
|
||||
DisplayName = displayName ?? throw new ArgumentNullException(nameof(displayName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the function to call to get the value of the property
|
||||
/// </summary>
|
||||
public Func<TProperty> Getter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the action to call to set the value of the property
|
||||
/// </summary>
|
||||
public Action<TProperty?> Setter { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DisplayName { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Type ValueType => typeof(TProperty);
|
||||
|
||||
/// <inheritdoc />
|
||||
public object? GetValue()
|
||||
{
|
||||
return Getter();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetValue(object? value)
|
||||
{
|
||||
if (value is TProperty match)
|
||||
Setter(match);
|
||||
else
|
||||
throw new ArgumentException("Value must match the type of the data binding registration", nameof(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Artemis.Storage.Entities.Profile.DataBindings;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class DataBindingRegistration<TLayerProperty, TProperty> : IDataBindingRegistration
|
||||
{
|
||||
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));
|
||||
Getter = getter ?? throw new ArgumentNullException(nameof(getter));
|
||||
Setter = setter ?? throw new ArgumentNullException(nameof(setter));
|
||||
DisplayName = displayName ?? throw new ArgumentNullException(nameof(displayName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layer property this registration was made on
|
||||
/// </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 function to call to get the value of the property
|
||||
/// </summary>
|
||||
public Func<TProperty> Getter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the action to call to set the value of the property
|
||||
/// </summary>
|
||||
public Action<TProperty> Setter { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DisplayName { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Type ValueType => typeof(TProperty);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data binding created using this registration
|
||||
/// </summary>
|
||||
public DataBinding<TLayerProperty, TProperty>? DataBinding { get; internal set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IDataBinding? GetDataBinding()
|
||||
{
|
||||
return DataBinding;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IDataBinding? CreateDataBinding()
|
||||
{
|
||||
if (DataBinding != null)
|
||||
return DataBinding;
|
||||
|
||||
DataBindingEntity? dataBinding = LayerProperty.Entity.DataBindingEntities.FirstOrDefault(e => e.Identifier == DisplayName);
|
||||
if (dataBinding == null)
|
||||
return null;
|
||||
|
||||
DataBinding = new DataBinding<TLayerProperty, TProperty>(LayerProperty, dataBinding);
|
||||
return DataBinding;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ClearDataBinding()
|
||||
{
|
||||
if (DataBinding == null)
|
||||
return;
|
||||
|
||||
// The related entity is left behind, just in case the data binding is added back later
|
||||
LayerProperty.DisableDataBinding(DataBinding);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object? GetValue()
|
||||
{
|
||||
return Getter();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using Artemis.Core.Modules;
|
||||
|
||||
namespace Artemis.Core
|
||||
@@ -7,22 +8,51 @@ namespace Artemis.Core
|
||||
/// Represents a data binding that binds a certain <see cref="LayerProperty{T}" /> to a value inside a
|
||||
/// <see cref="DataModel" />
|
||||
/// </summary>
|
||||
public interface IDataBinding : IStorageModel, IUpdateModel, IDisposable
|
||||
public interface IDataBinding : IStorageModel, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the smoothing progress of the data binding and recalculates the value next <see cref="Apply" /> call
|
||||
/// Gets the layer property the data binding is applied to
|
||||
/// </summary>
|
||||
/// <param name="delta">The delta to apply during update</param>
|
||||
void UpdateWithDelta(TimeSpan delta);
|
||||
ILayerProperty BaseLayerProperty { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Applies the data binding to the layer property
|
||||
/// Gets a list of sub-properties this data binding applies to
|
||||
/// </summary>
|
||||
ReadOnlyCollection<IDataBindingProperty> Properties { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the data binding is enabled or not
|
||||
/// </summary>
|
||||
bool IsEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Applies the pending value of the data binding to the property
|
||||
/// </summary>
|
||||
void Apply();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// If the data binding is enabled, loads the node script for that data binding
|
||||
/// </summary>
|
||||
void LoadNodeScript();
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a data binding property has been added
|
||||
/// </summary>
|
||||
public event EventHandler<DataBindingEventArgs>? DataBindingPropertyRegistered;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when all data binding properties have been removed
|
||||
/// </summary>
|
||||
public event EventHandler<DataBindingEventArgs>? DataBindingPropertiesCleared;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a data binding has been enabled
|
||||
/// </summary>
|
||||
public event EventHandler<DataBindingEventArgs>? DataBindingEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a data binding has been disabled
|
||||
/// </summary>
|
||||
public event EventHandler<DataBindingEventArgs>? DataBindingDisabled;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a data binding converter that acts as the bridge between a
|
||||
/// <see cref="DataBinding{TLayerProperty, TProperty}" /> and a <see cref="LayerProperty{T}" />
|
||||
/// </summary>
|
||||
public interface IDataBindingConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type this converter supports
|
||||
/// </summary>
|
||||
public Type SupportedType { get; }
|
||||
}
|
||||
}
|
||||
+8
-18
@@ -5,7 +5,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Represents a data binding registration
|
||||
/// </summary>
|
||||
public interface IDataBindingRegistration
|
||||
public interface IDataBindingProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the display name of the data binding registration
|
||||
@@ -18,25 +18,15 @@ namespace Artemis.Core
|
||||
Type ValueType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the data binding applied using this registration
|
||||
/// </summary>
|
||||
public IDataBinding? GetDataBinding();
|
||||
|
||||
/// <summary>
|
||||
/// If found, creates a data binding from storage
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IDataBinding? CreateDataBinding();
|
||||
|
||||
/// <summary>
|
||||
/// If present, removes the current data binding
|
||||
/// </summary>
|
||||
void ClearDataBinding();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the data binding
|
||||
/// Gets the value of the property this registration points to
|
||||
/// </summary>
|
||||
/// <returns>A value matching the type of <see cref="ValueType" /></returns>
|
||||
object? GetValue();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of the property this registration points to
|
||||
/// </summary>
|
||||
/// <param name="value">A value matching the type of <see cref="ValueType" /></param>
|
||||
void SetValue(object? value);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
|
||||
namespace Artemis.Core
|
||||
@@ -23,6 +22,21 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
LayerPropertyGroup LayerPropertyGroup { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data binding of this property
|
||||
/// </summary>
|
||||
IDataBinding BaseDataBinding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the layer has any data binding properties
|
||||
/// </summary>
|
||||
public bool HasDataBinding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether data bindings are supported on this type of property
|
||||
/// </summary>
|
||||
public bool DataBindingsSupported { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique path of the property on the layer
|
||||
/// </summary>
|
||||
@@ -47,11 +61,6 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
void Initialize(RenderProfileElement profileElement, LayerPropertyGroup group, PropertyEntity entity, bool fromStorage, PropertyDescriptionAttribute description, string path);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list off all data binding registrations
|
||||
/// </summary>
|
||||
List<IDataBindingRegistration> GetAllDataBindingRegistrations();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load and add the provided keyframe entity to the layer property
|
||||
/// </summary>
|
||||
@@ -70,6 +79,12 @@ namespace Artemis.Core
|
||||
/// <param name="timeline">The timeline to apply to the property</param>
|
||||
void Update(Timeline timeline);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updates just the data binding instead of the entire layer
|
||||
/// </summary>
|
||||
void UpdateDataBinding();
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the layer property is disposed
|
||||
/// </summary>
|
||||
@@ -104,25 +119,5 @@ namespace Artemis.Core
|
||||
/// Occurs when a keyframe was removed from the layer property
|
||||
/// </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>
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a data binding has been disabled
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingDisabled;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ namespace Artemis.Core
|
||||
Path = null!;
|
||||
Entity = null!;
|
||||
PropertyDescription = null!;
|
||||
DataBinding = null!;
|
||||
|
||||
CurrentValue = default!;
|
||||
DefaultValue = default!;
|
||||
@@ -57,93 +58,10 @@ namespace Artemis.Core
|
||||
{
|
||||
_disposed = true;
|
||||
|
||||
foreach (IDataBinding dataBinding in _dataBindings)
|
||||
dataBinding.Dispose();
|
||||
|
||||
DataBinding.Dispose();
|
||||
Disposed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="Updated" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnUpdated()
|
||||
{
|
||||
Updated?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="CurrentValueSet" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnCurrentValueSet()
|
||||
{
|
||||
CurrentValueSet?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
LayerPropertyGroup.OnLayerPropertyOnCurrentValueSet(new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="VisibilityChanged" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnVisibilityChanged()
|
||||
{
|
||||
VisibilityChanged?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="KeyframesToggled" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnKeyframesToggled()
|
||||
{
|
||||
KeyframesToggled?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="KeyframeAdded" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnKeyframeAdded()
|
||||
{
|
||||
KeyframeAdded?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="KeyframeRemoved" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnKeyframeRemoved()
|
||||
{
|
||||
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>
|
||||
protected virtual void OnDataBindingEnabled(LayerPropertyEventArgs e)
|
||||
{
|
||||
DataBindingEnabled?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DataBindingDisabled" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDataBindingDisabled(LayerPropertyEventArgs e)
|
||||
{
|
||||
DataBindingDisabled?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public PropertyDescriptionAttribute PropertyDescription { get; internal set; }
|
||||
|
||||
@@ -162,7 +80,16 @@ namespace Artemis.Core
|
||||
CurrentValue = BaseValue;
|
||||
|
||||
UpdateKeyframes(timeline);
|
||||
UpdateDataBindings(timeline);
|
||||
UpdateDataBinding();
|
||||
|
||||
// UpdateDataBinding called OnUpdated()
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void UpdateDataBinding()
|
||||
{
|
||||
DataBinding.Update();
|
||||
DataBinding.Apply();
|
||||
|
||||
OnUpdated();
|
||||
}
|
||||
@@ -174,39 +101,6 @@ namespace Artemis.Core
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler? Disposed;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? Updated;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? CurrentValueSet;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? VisibilityChanged;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? KeyframesToggled;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? KeyframeAdded;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? KeyframeRemoved;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingPropertyRegistered;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingPropertiesCleared;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingEnabled;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? DataBindingDisabled;
|
||||
|
||||
#region Hierarchy
|
||||
|
||||
private bool _isHidden;
|
||||
@@ -480,137 +374,19 @@ namespace Artemis.Core
|
||||
|
||||
#region Data bindings
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
internal readonly List<IDataBindingRegistration> _dataBindingRegistrations = new();
|
||||
|
||||
internal readonly List<IDataBinding> _dataBindings = new();
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether data bindings are supported on this type of property
|
||||
/// Gets the data binding of this property
|
||||
/// </summary>
|
||||
public bool DataBindingsSupported { get; protected internal set; } = true;
|
||||
public DataBinding<T> DataBinding { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the layer has any active data bindings
|
||||
/// </summary>
|
||||
public bool HasDataBinding => GetAllDataBindingRegistrations().Any(r => r.GetDataBinding() != null);
|
||||
/// <inheritdoc />
|
||||
public bool DataBindingsSupported => DataBinding.Properties.Any();
|
||||
|
||||
/// <summary>
|
||||
/// 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>(string identifier)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("LayerProperty");
|
||||
/// <inheritdoc />
|
||||
public IDataBinding BaseDataBinding => DataBinding;
|
||||
|
||||
IDataBindingRegistration? match = _dataBindingRegistrations.FirstOrDefault(r => r is DataBindingRegistration<T, TProperty> registration &&
|
||||
registration.DisplayName == identifier);
|
||||
return (DataBindingRegistration<T, TProperty>?) match;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list containing all data binding registrations of this layer property
|
||||
/// </summary>
|
||||
/// <returns>A list containing all data binding registrations of this layer property</returns>
|
||||
public List<IDataBindingRegistration> GetAllDataBindingRegistrations()
|
||||
{
|
||||
return _dataBindingRegistrations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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="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>
|
||||
/// <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);
|
||||
|
||||
// If not yet initialized, load the data binding related to the registration if available
|
||||
if (_isInitialized)
|
||||
{
|
||||
IDataBinding? dataBinding = registration.CreateDataBinding();
|
||||
if (dataBinding != null)
|
||||
_dataBindings.Add(dataBinding);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
foreach (IDataBindingRegistration dataBindingRegistration in _dataBindingRegistrations)
|
||||
dataBindingRegistration.ClearDataBinding();
|
||||
_dataBindingRegistrations.Clear();
|
||||
|
||||
OnDataBindingPropertiesCleared();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables a data binding for the provided <paramref name="dataBindingRegistration" />
|
||||
/// </summary>
|
||||
/// <returns>The newly created data binding</returns>
|
||||
public DataBinding<T, TProperty> EnableDataBinding<TProperty>(DataBindingRegistration<T, TProperty> dataBindingRegistration)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("LayerProperty");
|
||||
|
||||
if (dataBindingRegistration.LayerProperty != this)
|
||||
throw new ArtemisCoreException("Cannot enable a data binding using a data binding registration of a different layer property");
|
||||
if (dataBindingRegistration.DataBinding != null)
|
||||
throw new ArtemisCoreException("Provided data binding registration already has an enabled data binding");
|
||||
|
||||
DataBinding<T, TProperty> dataBinding = new(dataBindingRegistration);
|
||||
_dataBindings.Add(dataBinding);
|
||||
|
||||
OnDataBindingEnabled(new LayerPropertyEventArgs(dataBinding.LayerProperty));
|
||||
return dataBinding;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables the provided data binding
|
||||
/// </summary>
|
||||
/// <param name="dataBinding">The data binding to remove</param>
|
||||
public void DisableDataBinding<TProperty>(DataBinding<T, TProperty> dataBinding)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("LayerProperty");
|
||||
|
||||
_dataBindings.Remove(dataBinding);
|
||||
|
||||
if (dataBinding.Registration != null)
|
||||
dataBinding.Registration.DataBinding = null;
|
||||
dataBinding.Dispose();
|
||||
OnDataBindingDisabled(new LayerPropertyEventArgs(dataBinding.LayerProperty));
|
||||
}
|
||||
|
||||
private void UpdateDataBindings(Timeline timeline)
|
||||
{
|
||||
foreach (IDataBinding dataBinding in _dataBindings)
|
||||
{
|
||||
dataBinding.Update(timeline);
|
||||
dataBinding.Apply();
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool HasDataBinding => DataBinding.IsEnabled;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -694,6 +470,7 @@ namespace Artemis.Core
|
||||
Entity = entity ?? throw new ArgumentNullException(nameof(entity));
|
||||
PropertyDescription = description ?? throw new ArgumentNullException(nameof(description));
|
||||
IsLoadedFromStorage = fromStorage;
|
||||
DataBinding = new DataBinding<T>(this);
|
||||
|
||||
if (PropertyDescription.DisableKeyframes)
|
||||
KeyframesSupported = false;
|
||||
@@ -737,13 +514,7 @@ namespace Artemis.Core
|
||||
// ignored for now
|
||||
}
|
||||
|
||||
_dataBindings.Clear();
|
||||
foreach (IDataBindingRegistration dataBindingRegistration in _dataBindingRegistrations)
|
||||
{
|
||||
IDataBinding? dataBinding = dataBindingRegistration.CreateDataBinding();
|
||||
if (dataBinding != null)
|
||||
_dataBindings.Add(dataBinding);
|
||||
}
|
||||
DataBinding.Load();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -762,9 +533,8 @@ namespace Artemis.Core
|
||||
Entity.KeyframeEntities.Clear();
|
||||
Entity.KeyframeEntities.AddRange(Keyframes.Select(k => k.GetKeyframeEntity()));
|
||||
|
||||
Entity.DataBindingEntities.Clear();
|
||||
foreach (IDataBinding dataBinding in _dataBindings)
|
||||
dataBinding.Save();
|
||||
DataBinding.Save();
|
||||
Entity.DataBinding = DataBinding.Entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -775,5 +545,79 @@ namespace Artemis.Core
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler? Disposed;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? Updated;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? CurrentValueSet;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? VisibilityChanged;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? KeyframesToggled;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? KeyframeAdded;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<LayerPropertyEventArgs>? KeyframeRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="Updated" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnUpdated()
|
||||
{
|
||||
Updated?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="CurrentValueSet" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnCurrentValueSet()
|
||||
{
|
||||
CurrentValueSet?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
LayerPropertyGroup.OnLayerPropertyOnCurrentValueSet(new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="VisibilityChanged" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnVisibilityChanged()
|
||||
{
|
||||
VisibilityChanged?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="KeyframesToggled" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnKeyframesToggled()
|
||||
{
|
||||
KeyframesToggled?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="KeyframeAdded" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnKeyframeAdded()
|
||||
{
|
||||
KeyframeAdded?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="KeyframeRemoved" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnKeyframeRemoved()
|
||||
{
|
||||
KeyframeRemoved?.Invoke(this, new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -113,11 +113,8 @@ namespace Artemis.Core
|
||||
? new NodeScript<bool>($"Activate {_typeDisplayName}", $"Whether or not this {_typeDisplayName} should be active", RenderElementEntity.NodeScript, Profile)
|
||||
: new NodeScript<bool>($"Activate {_typeDisplayName}", $"Whether or not this {_typeDisplayName} should be active", Profile);
|
||||
|
||||
foreach (ILayerProperty layerProperty in GetAllLayerProperties())
|
||||
{
|
||||
foreach (IDataBindingRegistration dataBindingRegistration in layerProperty.GetAllDataBindingRegistrations())
|
||||
dataBindingRegistration.GetDataBinding()?.LoadNodeScript();
|
||||
}
|
||||
foreach (ILayerProperty layerProperty in GetAllLayerProperties())
|
||||
layerProperty.BaseDataBinding.LoadNodeScript();
|
||||
}
|
||||
|
||||
internal void OnLayerEffectsUpdated()
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using Artemis.Core.Internal;
|
||||
using Artemis.Storage.Entities.Profile.Nodes;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
public class DataBindingNodeScript<TLayerProperty> : NodeScript
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
internal DataBindingExitNode<TLayerProperty> DataBindingExitNode { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Type ResultType => typeof(object);
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
public DataBindingNodeScript(string name, string description, DataBinding<TLayerProperty> dataBinding, object? context = null)
|
||||
: base(name, description, context)
|
||||
{
|
||||
DataBindingExitNode = new DataBindingExitNode<TLayerProperty>(dataBinding);
|
||||
ExitNode = DataBindingExitNode;
|
||||
AddNode(ExitNode);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public DataBindingNodeScript(string name, string description, DataBinding<TLayerProperty> dataBinding, NodeScriptEntity entity, object? context = null)
|
||||
: base(name, description, entity, context)
|
||||
{
|
||||
DataBindingExitNode = new DataBindingExitNode<TLayerProperty>(dataBinding);
|
||||
ExitNode = DataBindingExitNode;
|
||||
AddNode(ExitNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ namespace Artemis.Core
|
||||
|
||||
private void Evaluate()
|
||||
{
|
||||
Value = ConnectedTo.Count > 0 ? ConnectedTo[0].PinValue : default;
|
||||
Value = ConnectedTo.Count > 0 ? ConnectedTo[0].PinValue : Type.GetDefault();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Artemis.Core.Internal
|
||||
{
|
||||
internal class DataBindingExitNode<TLayerProperty> : Node, IExitNode
|
||||
{
|
||||
private readonly Dictionary<IDataBindingProperty, InputPin> _propertyPins = new();
|
||||
private readonly Dictionary<IDataBindingProperty, object> _propertyValues = new();
|
||||
|
||||
public DataBinding<TLayerProperty> DataBinding { get; }
|
||||
|
||||
public DataBindingExitNode(DataBinding<TLayerProperty> dataBinding) : base(dataBinding.LayerProperty.PropertyDescription.Name ?? "", "")
|
||||
{
|
||||
DataBinding = dataBinding;
|
||||
DataBinding.DataBindingPropertiesCleared += DataBindingOnDataBindingPropertiesCleared;
|
||||
DataBinding.DataBindingPropertyRegistered += DataBindingOnDataBindingPropertyRegistered;
|
||||
|
||||
CreateInputPins();
|
||||
}
|
||||
|
||||
public override bool IsExitNode => true;
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
foreach (var (property, inputPin) in _propertyPins)
|
||||
{
|
||||
if (inputPin.ConnectedTo.Any())
|
||||
_propertyValues[property] = inputPin.Value;
|
||||
else
|
||||
_propertyValues.Remove(property);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyToDataBinding()
|
||||
{
|
||||
foreach (var (property, pendingValue) in _propertyValues)
|
||||
property.SetValue(pendingValue);
|
||||
}
|
||||
|
||||
private void ClearInputPins()
|
||||
{
|
||||
while (Pins.Any())
|
||||
RemovePin((Pin) Pins.First());
|
||||
|
||||
_propertyPins.Clear();
|
||||
_propertyValues.Clear();
|
||||
}
|
||||
|
||||
private void CreateInputPins()
|
||||
{
|
||||
ClearInputPins();
|
||||
|
||||
foreach (IDataBindingProperty property in DataBinding.Properties)
|
||||
_propertyPins.Add(property, CreateInputPin(property.ValueType, property.DisplayName));
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void DataBindingOnDataBindingPropertyRegistered(object? sender, DataBindingEventArgs e)
|
||||
{
|
||||
CreateInputPins();
|
||||
}
|
||||
|
||||
private void DataBindingOnDataBindingPropertiesCleared(object? sender, DataBindingEventArgs e)
|
||||
{
|
||||
ClearInputPins();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user