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:
parent
4746719f9d
commit
b19cc6ca54
@ -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
|
||||
}
|
||||
}
|
||||
@ -51,7 +51,7 @@ namespace Artemis.Core
|
||||
{
|
||||
return DataBinding;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public IDataBinding CreateDataBinding()
|
||||
{
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user