1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Core - Added conditional data bindings

This commit is contained in:
Robert 2020-09-22 22:04:48 +02:00
parent 4746719f9d
commit b19cc6ca54
12 changed files with 289 additions and 64 deletions

View File

@ -177,7 +177,7 @@ namespace Artemis.Core
var easingAmount = _easingProgress.TotalSeconds / EasingTime.TotalSeconds; var easingAmount = _easingProgress.TotalSeconds / EasingTime.TotalSeconds;
return Converter.Interpolate(_previousValue, _currentValue, Easings.Interpolate(easingAmount, EasingFunction)); return Converter.Interpolate(_previousValue, _currentValue, Easings.Interpolate(easingAmount, EasingFunction));
} }
#region Mode management #region Mode management
/// <summary> /// <summary>
@ -218,7 +218,7 @@ namespace Artemis.Core
} }
#endregion #endregion
#region Storage #region Storage
/// <inheritdoc /> /// <inheritdoc />
@ -262,7 +262,7 @@ namespace Artemis.Core
public enum DataBindingModeType public enum DataBindingModeType
{ {
/// <summary> /// <summary>
/// Disables the data binding /// Disables the data binding
/// </summary> /// </summary>
None, None,
@ -272,8 +272,8 @@ namespace Artemis.Core
Direct, Direct,
/// <summary> /// <summary>
/// Replaces the layer property value with the data binding value /// Replaces the layer property value with the data binding value
/// </summary> /// </summary>
Conditional, Conditional
} }
} }

View File

@ -51,7 +51,7 @@ namespace Artemis.Core
{ {
return DataBinding; return DataBinding;
} }
/// <inheritdoc /> /// <inheritdoc />
public IDataBinding CreateDataBinding() public IDataBinding CreateDataBinding()
{ {

View File

@ -1,4 +1,7 @@
using Artemis.Storage.Entities.Profile.DataBindings; using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Storage.Entities.Profile.DataBindings;
namespace Artemis.Core namespace Artemis.Core
{ {
@ -7,42 +10,130 @@ namespace Artemis.Core
/// </summary> /// </summary>
public class ConditionalDataBinding<TLayerProperty, TProperty> : IDataBindingMode<TLayerProperty, TProperty> public class ConditionalDataBinding<TLayerProperty, TProperty> : IDataBindingMode<TLayerProperty, TProperty>
{ {
private readonly List<DataBindingCondition<TLayerProperty, TProperty>> _conditions = new List<DataBindingCondition<TLayerProperty, TProperty>>();
private bool _disposed;
internal ConditionalDataBinding(DataBinding<TLayerProperty, TProperty> dataBinding, ConditionalDataBindingEntity entity) internal ConditionalDataBinding(DataBinding<TLayerProperty, TProperty> dataBinding, ConditionalDataBindingEntity entity)
{ {
DataBinding = dataBinding; DataBinding = dataBinding;
Entity = entity; Entity = entity;
} }
internal ConditionalDataBindingEntity Entity { get; }
/// <summary>
/// Gets a list of conditions applied to this data binding
/// </summary>
public IReadOnlyList<DataBindingCondition<TLayerProperty, TProperty>> Conditions => _conditions.AsReadOnly();
/// <inheritdoc /> /// <inheritdoc />
public DataBinding<TLayerProperty, TProperty> DataBinding { get; } public DataBinding<TLayerProperty, TProperty> DataBinding { get; }
/// <inheritdoc /> /// <inheritdoc />
public TProperty GetValue(TProperty baseValue) public TProperty GetValue(TProperty baseValue)
{ {
return default; if (_disposed)
throw new ObjectDisposedException("ConditionalDataBinding");
var condition = Conditions.FirstOrDefault(c => c.Evaluate());
return condition == null ? baseValue : condition.Value;
} }
internal ConditionalDataBindingEntity Entity { get; }
#region Storage
/// <inheritdoc />
public void Load()
{
}
/// <inheritdoc />
public void Save()
{
}
#endregion
#region IDisposable #region IDisposable
/// <inheritdoc /> /// <inheritdoc />
public void Dispose() public void Dispose()
{ {
_disposed = true;
foreach (var dataBindingCondition in Conditions)
dataBindingCondition.Dispose();
}
#endregion
#region Values
/// <summary>
/// Adds a condition to the conditional data binding's <see cref="Conditions" /> collection
/// </summary>
/// <returns>The newly created <see cref="DataBindingCondition{TLayerProperty,TProperty}" /></returns>
public DataBindingCondition<TLayerProperty, TProperty> AddCondition()
{
if (_disposed)
throw new ObjectDisposedException("ConditionalDataBinding");
var condition = new DataBindingCondition<TLayerProperty, TProperty>(this);
_conditions.Add(condition);
ApplyOrder();
OnConditionsUpdated();
return condition;
}
/// <summary>
/// Removes a condition from the conditional data binding's <see cref="Conditions" /> collection and disposes it
/// </summary>
/// <param name="condition"></param>
public void RemoveCondition(DataBindingCondition<TLayerProperty, TProperty> condition)
{
if (_disposed)
throw new ObjectDisposedException("ConditionalDataBinding");
if (!_conditions.Contains(condition))
return;
_conditions.Remove(condition);
condition.Dispose();
ApplyOrder();
OnConditionsUpdated();
}
internal void ApplyOrder()
{
_conditions.Sort((a, b) => a.Order.CompareTo(b.Order));
for (var index = 0; index < _conditions.Count; index++)
{
var condition = _conditions[index];
condition.Order = index + 1;
}
}
#endregion
#region Storage
/// <inheritdoc />
public void Load()
{
foreach (var dataBindingConditionEntity in Entity.Values)
_conditions.Add(new DataBindingCondition<TLayerProperty, TProperty>(this, dataBindingConditionEntity));
ApplyOrder();
}
/// <inheritdoc />
public void Save()
{
Entity.Values.Clear();
foreach (var dataBindingCondition in Conditions)
dataBindingCondition.Save();
}
#endregion
#region Events
/// <summary>
/// Occurs when a condition is added or removed
/// </summary>
public event EventHandler ConditionsUpdated;
protected virtual void OnConditionsUpdated()
{
ConditionsUpdated?.Invoke(this, EventArgs.Empty);
} }
#endregion #endregion

View File

@ -0,0 +1,107 @@
using System;
using Artemis.Storage.Entities.Profile.DataBindings;
using Newtonsoft.Json;
namespace Artemis.Core
{
/// <inheritdoc />
public class DataBindingCondition<TLayerProperty, TProperty> : IDataBindingCondition
{
private bool _disposed;
/// <summary>
/// Creates a new instance of the <see cref="DataBindingCondition{TLayerProperty,TProperty}" /> class
/// </summary>
/// <param name="conditionalDataBinding">The conditional data binding this condition is applied too</param>
public DataBindingCondition(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding)
{
ConditionalDataBinding = conditionalDataBinding ?? throw new ArgumentNullException(nameof(conditionalDataBinding));
Order = conditionalDataBinding.Conditions.Count + 1;
Entity = new DataBindingConditionEntity();
Save();
}
internal DataBindingCondition(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding, DataBindingConditionEntity entity)
{
ConditionalDataBinding = conditionalDataBinding ?? throw new ArgumentNullException(nameof(conditionalDataBinding));
Entity = entity;
Load();
}
/// <summary>
/// Gets the conditional data binding this condition is applied to
/// </summary>
public ConditionalDataBinding<TLayerProperty, TProperty> ConditionalDataBinding { get; }
/// <summary>
/// Gets the position at which the modifier appears on the data binding
/// </summary>
public int Order { get; internal set; }
/// <summary>
/// Gets or sets the value to be applied when the condition is met
/// </summary>
public TProperty Value { get; set; }
/// <summary>
/// Gets the root group of the condition that must be met
/// </summary>
public DataModelConditionGroup Condition { get; private set; }
internal DataBindingConditionEntity Entity { get; set; }
/// <inheritdoc />
public bool Evaluate()
{
return Condition.Evaluate();
}
/// <inheritdoc />
public void Save()
{
if (_disposed)
throw new ObjectDisposedException("DataBindingCondition");
if (!ConditionalDataBinding.Entity.Values.Contains(Entity))
ConditionalDataBinding.Entity.Values.Add(Entity);
Entity.Condition = Condition.Entity;
Condition.Save();
Entity.Value = JsonConvert.SerializeObject(Value);
Entity.Order = Order;
}
/// <inheritdoc />
public void Load()
{
if (_disposed)
throw new ObjectDisposedException("DataBindingCondition");
Condition = Entity.Condition != null
? new DataModelConditionGroup(null, Entity.Condition)
: new DataModelConditionGroup(null);
Value = JsonConvert.DeserializeObject<TProperty>(Entity.Value);
Order = Entity.Order;
}
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
Condition.Dispose();
}
/// <summary>
/// Updates the order and resorts the Conditions list in the <see cref="ConditionalDataBinding" />
/// </summary>
/// <param name="order"></param>
public void UpdateOrder(int order)
{
Order = order;
ConditionalDataBinding.ApplyOrder();
}
}
}

View File

@ -12,14 +12,10 @@ namespace Artemis.Core
{ {
private bool _disposed; private bool _disposed;
/// <summary> internal DataBindingModifier(DirectDataBinding<TLayerProperty, TProperty> directDataBinding, ProfileRightSideType parameterType)
/// Creates a new instance of the <see cref="DataBindingModifier{TLayerProperty,TProperty}" /> class
/// </summary>
/// <param name="directDataBinding">The direct data binding the modifier is to be applied to</param>
/// <param name="parameterType">The type of the parameter, can either be dynamic (based on a data model value) or static</param>
public DataBindingModifier(DirectDataBinding<TLayerProperty, TProperty> directDataBinding, ProfileRightSideType parameterType)
{ {
DirectDataBinding = directDataBinding ?? throw new ArgumentNullException(nameof(directDataBinding)); DirectDataBinding = directDataBinding ?? throw new ArgumentNullException(nameof(directDataBinding));
Order = directDataBinding.Modifiers.Count + 1;
ParameterType = parameterType; ParameterType = parameterType;
Entity = new DataBindingModifierEntity(); Entity = new DataBindingModifierEntity();
Initialize(); Initialize();
@ -40,7 +36,7 @@ namespace Artemis.Core
public DataBindingModifierType ModifierType { get; private set; } public DataBindingModifierType ModifierType { get; private set; }
/// <summary> /// <summary>
/// Gets the direct data binding this modifier is applied to /// Gets the direct data binding this modifier is applied to
/// </summary> /// </summary>
public DirectDataBinding<TLayerProperty, TProperty> DirectDataBinding { get; } public DirectDataBinding<TLayerProperty, TProperty> DirectDataBinding { get; }
@ -123,6 +119,17 @@ namespace Artemis.Core
// Parameter is done during initialize // Parameter is done during initialize
} }
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
DataBindingModifierTypeStore.DataBindingModifierAdded -= DataBindingModifierTypeStoreOnDataBindingModifierAdded;
DataBindingModifierTypeStore.DataBindingModifierRemoved -= DataBindingModifierTypeStoreOnDataBindingModifierRemoved;
DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded;
DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved;
}
/// <summary> /// <summary>
/// Applies the modifier to the provided value /// Applies the modifier to the provided value
/// </summary> /// </summary>
@ -339,23 +346,12 @@ namespace Artemis.Core
private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e) private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e)
{ {
if (e.Registration.DataModel != ParameterDataModel) if (e.Registration.DataModel != ParameterDataModel)
return; return;
ParameterDataModel = null; ParameterDataModel = null;
CompiledParameterAccessor = null; CompiledParameterAccessor = null;
} }
#endregion #endregion
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
DataBindingModifierTypeStore.DataBindingModifierAdded -= DataBindingModifierTypeStoreOnDataBindingModifierAdded;
DataBindingModifierTypeStore.DataBindingModifierRemoved -= DataBindingModifierTypeStoreOnDataBindingModifierRemoved;
DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded;
DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved;
}
} }
} }

View File

@ -24,9 +24,6 @@ namespace Artemis.Core
Load(); Load();
} }
/// <inheritdoc />
public DataBinding<TLayerProperty, TProperty> DataBinding { get; }
internal DirectDataBindingEntity Entity { get; } internal DirectDataBindingEntity Entity { get; }
/// <summary> /// <summary>
@ -49,11 +46,14 @@ namespace Artemis.Core
/// </summary> /// </summary>
public Func<DataModel, object> CompiledTargetAccessor { get; private set; } public Func<DataModel, object> CompiledTargetAccessor { get; private set; }
/// <inheritdoc />
public DataBinding<TLayerProperty, TProperty> DataBinding { get; }
/// <inheritdoc /> /// <inheritdoc />
public TProperty GetValue(TProperty baseValue) public TProperty GetValue(TProperty baseValue)
{ {
if (_disposed) if (_disposed)
throw new ObjectDisposedException("DataBinding"); throw new ObjectDisposedException("DirectDataBinding");
if (CompiledTargetAccessor == null) if (CompiledTargetAccessor == null)
return baseValue; return baseValue;
@ -91,6 +91,8 @@ namespace Artemis.Core
// Modifiers // Modifiers
foreach (var dataBindingModifierEntity in Entity.Modifiers) foreach (var dataBindingModifierEntity in Entity.Modifiers)
_modifiers.Add(new DataBindingModifier<TLayerProperty, TProperty>(this, dataBindingModifierEntity)); _modifiers.Add(new DataBindingModifier<TLayerProperty, TProperty>(this, dataBindingModifierEntity));
ApplyOrder();
} }
/// <inheritdoc /> /// <inheritdoc />
@ -156,7 +158,7 @@ namespace Artemis.Core
{ {
return SourceDataModel?.GetTypeAtPath(SourcePropertyPath); return SourceDataModel?.GetTypeAtPath(SourcePropertyPath);
} }
/// <summary> /// <summary>
/// Updates the source of the data binding and re-compiles the expression /// Updates the source of the data binding and re-compiles the expression
/// </summary> /// </summary>
@ -165,7 +167,7 @@ namespace Artemis.Core
public void UpdateSource(DataModel dataModel, string path) public void UpdateSource(DataModel dataModel, string path)
{ {
if (_disposed) if (_disposed)
throw new ObjectDisposedException("DataBinding"); throw new ObjectDisposedException("DirectDataBinding");
if (dataModel != null && path == null) if (dataModel != null && path == null)
throw new ArtemisCoreException("If a data model is provided, a path is also required"); throw new ArtemisCoreException("If a data model is provided, a path is also required");
@ -188,34 +190,47 @@ namespace Artemis.Core
#region Modifiers #region Modifiers
/// <summary> /// <summary>
/// Adds a modifier to the data binding's <see cref="Modifiers" /> collection /// Adds a modifier to the direct data binding's <see cref="Modifiers" /> collection
/// </summary> /// </summary>
/// <param name="type">The type of the parameter, can either be dynamic (based on a data model value) or static</param>
public DataBindingModifier<TLayerProperty, TProperty> AddModifier(ProfileRightSideType type) public DataBindingModifier<TLayerProperty, TProperty> AddModifier(ProfileRightSideType type)
{ {
if (_disposed) if (_disposed)
throw new ObjectDisposedException("DataBinding"); throw new ObjectDisposedException("DirectDataBinding");
var modifier = new DataBindingModifier<TLayerProperty, TProperty>(this, type); var modifier = new DataBindingModifier<TLayerProperty, TProperty>(this, type);
_modifiers.Add(modifier); _modifiers.Add(modifier);
ApplyOrder();
OnModifiersUpdated(); OnModifiersUpdated();
return modifier; return modifier;
} }
/// <summary> /// <summary>
/// Removes a modifier from the data binding's <see cref="Modifiers" /> collection and disposes it /// Removes a modifier from the direct data binding's <see cref="Modifiers" /> collection and disposes it
/// </summary> /// </summary>
public void RemoveModifier(DataBindingModifier<TLayerProperty, TProperty> modifier) public void RemoveModifier(DataBindingModifier<TLayerProperty, TProperty> modifier)
{ {
if (_disposed) if (_disposed)
throw new ObjectDisposedException("DataBinding"); throw new ObjectDisposedException("DirectDataBinding");
if (!_modifiers.Contains(modifier))
return;
if (_modifiers.Contains(modifier)) _modifiers.Remove(modifier);
modifier.Dispose();
ApplyOrder();
OnModifiersUpdated();
}
internal void ApplyOrder()
{
_modifiers.Sort((a, b) => a.Order.CompareTo(b.Order));
for (var index = 0; index < _modifiers.Count; index++)
{ {
_modifiers.Remove(modifier); var modifier = _modifiers[index];
modifier.Dispose(); modifier.Order = index + 1;
OnModifiersUpdated();
} }
} }

View File

@ -0,0 +1,15 @@
using System;
namespace Artemis.Core
{
/// <summary>
/// Represents a condition and a value inside a <see cref="ConditionalDataBinding{TLayerProperty,TProperty}" />
/// </summary>
public interface IDataBindingCondition : IStorageModel, IDisposable
{
/// <summary>
/// Evaluates the condition
/// </summary>
bool Evaluate();
}
}

View File

@ -3,7 +3,7 @@
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary> /// <summary>
/// Represents a data binding mode /// Represents a data binding mode
/// </summary> /// </summary>
public interface IDataBindingMode<TLayerProperty, TProperty> : IStorageModel, IDisposable public interface IDataBindingMode<TLayerProperty, TProperty> : IStorageModel, IDisposable
{ {
@ -19,4 +19,4 @@ namespace Artemis.Core
/// <returns></returns> /// <returns></returns>
TProperty GetValue(TProperty baseValue); TProperty GetValue(TProperty baseValue);
} }
} }

View File

@ -6,9 +6,9 @@ namespace Artemis.Storage.Entities.Profile.DataBindings
{ {
public ConditionalDataBindingEntity() public ConditionalDataBindingEntity()
{ {
Values = new List<DataBindingConditionValueEntity>(); Values = new List<DataBindingConditionEntity>();
} }
public List<DataBindingConditionValueEntity> Values { get; set; } public List<DataBindingConditionEntity> Values { get; set; }
} }
} }

View File

@ -2,9 +2,10 @@
namespace Artemis.Storage.Entities.Profile.DataBindings namespace Artemis.Storage.Entities.Profile.DataBindings
{ {
public class DataBindingConditionValueEntity public class DataBindingConditionEntity
{ {
public string Value { get; set; } public string Value { get; set; }
public DataModelConditionGroupEntity RootGroup { get; set; } public DataModelConditionGroupEntity Condition { get; set; }
public int Order { get; set; }
} }
} }