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

View File

@ -51,7 +51,7 @@ namespace Artemis.Core
{
return DataBinding;
}
/// <inheritdoc />
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
{
@ -7,42 +10,130 @@ namespace Artemis.Core
/// </summary>
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)
{
DataBinding = dataBinding;
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 />
public DataBinding<TLayerProperty, TProperty> DataBinding { get; }
/// <inheritdoc />
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
/// <inheritdoc />
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

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;
/// <summary>
/// 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)
internal DataBindingModifier(DirectDataBinding<TLayerProperty, TProperty> directDataBinding, ProfileRightSideType parameterType)
{
DirectDataBinding = directDataBinding ?? throw new ArgumentNullException(nameof(directDataBinding));
Order = directDataBinding.Modifiers.Count + 1;
ParameterType = parameterType;
Entity = new DataBindingModifierEntity();
Initialize();
@ -40,7 +36,7 @@ namespace Artemis.Core
public DataBindingModifierType ModifierType { get; private set; }
/// <summary>
/// Gets the direct data binding this modifier is applied to
/// Gets the direct data binding this modifier is applied to
/// </summary>
public DirectDataBinding<TLayerProperty, TProperty> DirectDataBinding { get; }
@ -123,6 +119,17 @@ namespace Artemis.Core
// Parameter is done during initialize
}
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
DataBindingModifierTypeStore.DataBindingModifierAdded -= DataBindingModifierTypeStoreOnDataBindingModifierAdded;
DataBindingModifierTypeStore.DataBindingModifierRemoved -= DataBindingModifierTypeStoreOnDataBindingModifierRemoved;
DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded;
DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved;
}
/// <summary>
/// Applies the modifier to the provided value
/// </summary>
@ -339,23 +346,12 @@ namespace Artemis.Core
private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e)
{
if (e.Registration.DataModel != ParameterDataModel)
if (e.Registration.DataModel != ParameterDataModel)
return;
ParameterDataModel = null;
CompiledParameterAccessor = null;
}
#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();
}
/// <inheritdoc />
public DataBinding<TLayerProperty, TProperty> DataBinding { get; }
internal DirectDataBindingEntity Entity { get; }
/// <summary>
@ -49,11 +46,14 @@ namespace Artemis.Core
/// </summary>
public Func<DataModel, object> CompiledTargetAccessor { get; private set; }
/// <inheritdoc />
public DataBinding<TLayerProperty, TProperty> DataBinding { get; }
/// <inheritdoc />
public TProperty GetValue(TProperty baseValue)
{
if (_disposed)
throw new ObjectDisposedException("DataBinding");
throw new ObjectDisposedException("DirectDataBinding");
if (CompiledTargetAccessor == null)
return baseValue;
@ -91,6 +91,8 @@ namespace Artemis.Core
// Modifiers
foreach (var dataBindingModifierEntity in Entity.Modifiers)
_modifiers.Add(new DataBindingModifier<TLayerProperty, TProperty>(this, dataBindingModifierEntity));
ApplyOrder();
}
/// <inheritdoc />
@ -156,7 +158,7 @@ namespace Artemis.Core
{
return SourceDataModel?.GetTypeAtPath(SourcePropertyPath);
}
/// <summary>
/// Updates the source of the data binding and re-compiles the expression
/// </summary>
@ -165,7 +167,7 @@ namespace Artemis.Core
public void UpdateSource(DataModel dataModel, string path)
{
if (_disposed)
throw new ObjectDisposedException("DataBinding");
throw new ObjectDisposedException("DirectDataBinding");
if (dataModel != null && path == null)
throw new ArtemisCoreException("If a data model is provided, a path is also required");
@ -188,34 +190,47 @@ namespace Artemis.Core
#region Modifiers
/// <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>
/// <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)
{
if (_disposed)
throw new ObjectDisposedException("DataBinding");
throw new ObjectDisposedException("DirectDataBinding");
var modifier = new DataBindingModifier<TLayerProperty, TProperty>(this, type);
_modifiers.Add(modifier);
ApplyOrder();
OnModifiersUpdated();
return modifier;
}
/// <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>
public void RemoveModifier(DataBindingModifier<TLayerProperty, TProperty> modifier)
{
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);
modifier.Dispose();
OnModifiersUpdated();
var modifier = _modifiers[index];
modifier.Order = index + 1;
}
}

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

View File

@ -6,9 +6,9 @@ namespace Artemis.Storage.Entities.Profile.DataBindings
{
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
{
public class DataBindingConditionValueEntity
public class DataBindingConditionEntity
{
public string Value { get; set; }
public DataModelConditionGroupEntity RootGroup { get; set; }
public DataModelConditionGroupEntity Condition { get; set; }
public int Order { get; set; }
}
}