Data bindings - Rewrote data binding system to fully leverage nodes

This commit is contained in:
Robert committed 2021-08-22 18:17:05 +02:00
1 parent 7933bf7ee9
commit 0bb93f2ebd
63 files changed
+654 -1533

No files matched your search

@@ -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
}
}