mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Data bindings - Added the option for different data binding modes
This commit is contained in:
parent
906efdac98
commit
f270d786f0
@ -16,6 +16,7 @@
|
|||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cconverters_005Cinternal/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cconverters_005Cinternal/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cdatabindingproperties/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cdatabindingproperties/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cdatabindingproperties_005Cabstract/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cdatabindingproperties_005Cabstract/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cmodes/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cmodifiers/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cmodifiers/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cmodifiers_005Cabstract/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cmodifiers_005Cabstract/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Clayerproperties/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Clayerproperties/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using Artemis.Core.DataModelExpansions;
|
|
||||||
using Artemis.Storage.Entities.Profile.DataBindings;
|
using Artemis.Storage.Entities.Profile.DataBindings;
|
||||||
|
|
||||||
namespace Artemis.Core
|
namespace Artemis.Core
|
||||||
@ -24,7 +21,7 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
ApplyRegistration(dataBindingRegistration);
|
ApplyRegistration(dataBindingRegistration);
|
||||||
Save();
|
Save();
|
||||||
Initialize();
|
ApplyDataBindingMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal DataBinding(LayerProperty<TLayerProperty> layerProperty, DataBindingEntity entity)
|
internal DataBinding(LayerProperty<TLayerProperty> layerProperty, DataBindingEntity entity)
|
||||||
@ -33,8 +30,8 @@ namespace Artemis.Core
|
|||||||
Entity = entity;
|
Entity = entity;
|
||||||
|
|
||||||
// Load will add children so be initialized before that
|
// Load will add children so be initialized before that
|
||||||
Initialize();
|
|
||||||
Load();
|
Load();
|
||||||
|
ApplyDataBindingMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -53,16 +50,9 @@ namespace Artemis.Core
|
|||||||
public DataBindingConverter<TLayerProperty, TProperty> Converter { get; private set; }
|
public DataBindingConverter<TLayerProperty, TProperty> Converter { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the currently used instance of the data model that contains the source of the data binding
|
/// Gets the data binding mode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DataModel SourceDataModel { get; private set; }
|
public IDataBindingMode<TLayerProperty, TProperty> DataBindingMode { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the path of the source property in the <see cref="SourceDataModel" />
|
|
||||||
/// </summary>
|
|
||||||
public string SourcePropertyPath { get; private set; }
|
|
||||||
|
|
||||||
public DataBindingMode Mode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the easing time of the data binding
|
/// Gets or sets the easing time of the data binding
|
||||||
@ -74,15 +64,6 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Easings.Functions EasingFunction { get; set; }
|
public Easings.Functions EasingFunction { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of modifiers applied to this data binding
|
|
||||||
/// </summary>
|
|
||||||
public IReadOnlyList<DataBindingModifier<TLayerProperty, TProperty>> Modifiers => _modifiers.AsReadOnly();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the compiled function that gets the current value of the data binding target
|
|
||||||
/// </summary>
|
|
||||||
public Func<DataModel, object> CompiledTargetAccessor { get; private set; }
|
|
||||||
|
|
||||||
internal DataBindingEntity Entity { get; }
|
internal DataBindingEntity Entity { get; }
|
||||||
|
|
||||||
@ -122,72 +103,9 @@ namespace Artemis.Core
|
|||||||
{
|
{
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
|
|
||||||
DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded;
|
DataBindingMode?.Dispose();
|
||||||
DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved;
|
|
||||||
|
|
||||||
foreach (var dataBindingModifier in Modifiers)
|
|
||||||
dataBindingModifier.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a modifier to the data binding's <see cref="Modifiers" /> collection
|
|
||||||
/// </summary>
|
|
||||||
public void AddModifier(DataBindingModifier<TLayerProperty, TProperty> modifier)
|
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
throw new ObjectDisposedException("DataBinding");
|
|
||||||
|
|
||||||
if (!_modifiers.Contains(modifier))
|
|
||||||
{
|
|
||||||
modifier.DataBinding = this;
|
|
||||||
_modifiers.Add(modifier);
|
|
||||||
|
|
||||||
OnModifiersUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes a modifier from the data binding's <see cref="Modifiers" /> collection
|
|
||||||
/// </summary>
|
|
||||||
public void RemoveModifier(DataBindingModifier<TLayerProperty, TProperty> modifier)
|
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
throw new ObjectDisposedException("DataBinding");
|
|
||||||
|
|
||||||
if (_modifiers.Contains(modifier))
|
|
||||||
{
|
|
||||||
modifier.DataBinding = null;
|
|
||||||
_modifiers.Remove(modifier);
|
|
||||||
|
|
||||||
OnModifiersUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the source of the data binding and re-compiles the expression
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dataModel">The data model of the source</param>
|
|
||||||
/// <param name="path">The path pointing to the source inside the data model</param>
|
|
||||||
public void UpdateSource(DataModel dataModel, string path)
|
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
throw new ObjectDisposedException("DataBinding");
|
|
||||||
|
|
||||||
if (dataModel != null && path == null)
|
|
||||||
throw new ArtemisCoreException("If a data model is provided, a path is also required");
|
|
||||||
if (dataModel == null && path != null)
|
|
||||||
throw new ArtemisCoreException("If path is provided, a data model is also required");
|
|
||||||
|
|
||||||
if (dataModel != null)
|
|
||||||
{
|
|
||||||
if (!dataModel.ContainsPath(path))
|
|
||||||
throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{path}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceDataModel = dataModel;
|
|
||||||
SourcePropertyPath = path;
|
|
||||||
CreateExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current value of the data binding
|
/// Gets the current value of the data binding
|
||||||
@ -199,15 +117,11 @@ namespace Artemis.Core
|
|||||||
if (_disposed)
|
if (_disposed)
|
||||||
throw new ObjectDisposedException("DataBinding");
|
throw new ObjectDisposedException("DataBinding");
|
||||||
|
|
||||||
if (CompiledTargetAccessor == null || Converter == null)
|
if (Converter == null || DataBindingMode == null)
|
||||||
return baseValue;
|
return baseValue;
|
||||||
|
|
||||||
var dataBindingValue = CompiledTargetAccessor(SourceDataModel);
|
var value = DataBindingMode.GetValue(baseValue);
|
||||||
foreach (var dataBindingModifier in Modifiers)
|
|
||||||
dataBindingValue = dataBindingModifier.Apply(dataBindingValue);
|
|
||||||
|
|
||||||
TProperty value = Converter.ConvertFromObject(dataBindingValue);
|
|
||||||
|
|
||||||
// If no easing is to be applied simple return whatever the current value is
|
// If no easing is to be applied simple return whatever the current value is
|
||||||
if (EasingTime == TimeSpan.Zero || !Converter.SupportsInterpolate)
|
if (EasingTime == TimeSpan.Zero || !Converter.SupportsInterpolate)
|
||||||
return value;
|
return value;
|
||||||
@ -228,28 +142,6 @@ namespace Artemis.Core
|
|||||||
return Registration.PropertyExpression.ReturnType;
|
return Registration.PropertyExpression.ReturnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the type of the source property of this data binding
|
|
||||||
/// </summary>
|
|
||||||
public Type GetSourceType()
|
|
||||||
{
|
|
||||||
return SourceDataModel?.GetTypeAtPath(SourcePropertyPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Initialize()
|
|
||||||
{
|
|
||||||
DataModelStore.DataModelAdded += DataModelStoreOnDataModelAdded;
|
|
||||||
DataModelStore.DataModelRemoved += DataModelStoreOnDataModelRemoved;
|
|
||||||
|
|
||||||
// Source
|
|
||||||
if (Entity.SourceDataModelGuid != null && SourceDataModel == null)
|
|
||||||
{
|
|
||||||
var dataModel = DataModelStore.Get(Entity.SourceDataModelGuid.Value)?.DataModel;
|
|
||||||
if (dataModel != null && dataModel.ContainsPath(Entity.SourcePropertyPath))
|
|
||||||
UpdateSource(dataModel, Entity.SourcePropertyPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResetEasing(TProperty value)
|
private void ResetEasing(TProperty value)
|
||||||
{
|
{
|
||||||
_previousValue = GetInterpolatedValue();
|
_previousValue = GetInterpolatedValue();
|
||||||
@ -284,25 +176,48 @@ 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
|
||||||
|
|
||||||
private void CreateExpression()
|
/// <summary>
|
||||||
|
/// Changes the data binding mode of the data binding to the specified <paramref name="dataBindingMode" />
|
||||||
|
/// </summary>
|
||||||
|
public void ChangeDataBindingMode(DataBindingModeType dataBindingMode)
|
||||||
{
|
{
|
||||||
var listType = SourceDataModel.GetListTypeInPath(SourcePropertyPath);
|
switch (dataBindingMode)
|
||||||
if (listType != null)
|
{
|
||||||
throw new ArtemisCoreException($"Cannot create a regular accessor at path {SourcePropertyPath} because the path contains a list");
|
case DataBindingModeType.Direct:
|
||||||
|
Entity.DataBindingMode = new DirectDataBindingEntity();
|
||||||
|
break;
|
||||||
|
case DataBindingModeType.Conditional:
|
||||||
|
Entity.DataBindingMode = new ConditionalDataBindingEntity();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Entity.DataBindingMode = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
var parameter = Expression.Parameter(typeof(DataModel), "targetDataModel");
|
ApplyDataBindingMode();
|
||||||
var accessor = SourcePropertyPath.Split('.').Aggregate<string, Expression>(
|
|
||||||
Expression.Convert(parameter, SourceDataModel.GetType()), // Cast to the appropriate type
|
|
||||||
Expression.Property
|
|
||||||
);
|
|
||||||
|
|
||||||
var returnValue = Expression.Convert(accessor, typeof(object));
|
|
||||||
|
|
||||||
var lambda = Expression.Lambda<Func<DataModel, object>>(returnValue, parameter);
|
|
||||||
CompiledTargetAccessor = lambda.Compile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ApplyDataBindingMode()
|
||||||
|
{
|
||||||
|
DataBindingMode?.Dispose();
|
||||||
|
DataBindingMode = null;
|
||||||
|
|
||||||
|
switch (Entity.DataBindingMode)
|
||||||
|
{
|
||||||
|
case DirectDataBindingEntity directDataBindingEntity:
|
||||||
|
DataBindingMode = new DirectDataBinding<TLayerProperty, TProperty>(this, directDataBindingEntity);
|
||||||
|
break;
|
||||||
|
case ConditionalDataBindingEntity conditionalDataBindingEntity:
|
||||||
|
DataBindingMode = new ConditionalDataBinding<TLayerProperty, TProperty>(this, conditionalDataBindingEntity);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Storage
|
#region Storage
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -314,15 +229,10 @@ namespace Artemis.Core
|
|||||||
var registration = LayerProperty.GetDataBindingRegistration<TProperty>(Entity.TargetExpression);
|
var registration = LayerProperty.GetDataBindingRegistration<TProperty>(Entity.TargetExpression);
|
||||||
ApplyRegistration(registration);
|
ApplyRegistration(registration);
|
||||||
|
|
||||||
Mode = (DataBindingMode) Entity.DataBindingMode;
|
|
||||||
EasingTime = Entity.EasingTime;
|
EasingTime = Entity.EasingTime;
|
||||||
EasingFunction = (Easings.Functions) Entity.EasingFunction;
|
EasingFunction = (Easings.Functions) Entity.EasingFunction;
|
||||||
|
|
||||||
// Data model is done during Initialize
|
DataBindingMode?.Load();
|
||||||
|
|
||||||
// Modifiers
|
|
||||||
foreach (var dataBindingModifierEntity in Entity.Modifiers)
|
|
||||||
_modifiers.Add(new DataBindingModifier<TLayerProperty, TProperty>(this, dataBindingModifierEntity));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -336,54 +246,10 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
// General
|
// General
|
||||||
Entity.TargetExpression = Registration.PropertyExpression.ToString();
|
Entity.TargetExpression = Registration.PropertyExpression.ToString();
|
||||||
Entity.DataBindingMode = (int) Mode;
|
|
||||||
Entity.EasingTime = EasingTime;
|
Entity.EasingTime = EasingTime;
|
||||||
Entity.EasingFunction = (int) EasingFunction;
|
Entity.EasingFunction = (int) EasingFunction;
|
||||||
|
|
||||||
// Data model
|
DataBindingMode?.Save();
|
||||||
if (SourceDataModel != null)
|
|
||||||
{
|
|
||||||
Entity.SourceDataModelGuid = SourceDataModel.PluginInfo.Guid;
|
|
||||||
Entity.SourcePropertyPath = SourcePropertyPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modifiers
|
|
||||||
Entity.Modifiers.Clear();
|
|
||||||
foreach (var dataBindingModifier in Modifiers)
|
|
||||||
dataBindingModifier.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Event handlers
|
|
||||||
|
|
||||||
private void DataModelStoreOnDataModelAdded(object sender, DataModelStoreEvent e)
|
|
||||||
{
|
|
||||||
var dataModel = e.Registration.DataModel;
|
|
||||||
if (dataModel.PluginInfo.Guid == Entity.SourceDataModelGuid && dataModel.ContainsPath(Entity.SourcePropertyPath))
|
|
||||||
UpdateSource(dataModel, Entity.SourcePropertyPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e)
|
|
||||||
{
|
|
||||||
if (SourceDataModel != e.Registration.DataModel)
|
|
||||||
return;
|
|
||||||
SourceDataModel = null;
|
|
||||||
CompiledTargetAccessor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Events
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs when a modifier is added or removed
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler ModifiersUpdated;
|
|
||||||
|
|
||||||
protected virtual void OnModifiersUpdated()
|
|
||||||
{
|
|
||||||
ModifiersUpdated?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -392,16 +258,21 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A mode that determines how the data binding is applied to the layer property
|
/// A mode that determines how the data binding is applied to the layer property
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum DataBindingMode
|
public enum DataBindingModeType
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Disables the data binding
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Replaces the layer property value with the data binding value
|
/// Replaces the layer property value with the data binding value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Replace,
|
Direct,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the data binding value to the layer property value
|
/// Replaces the layer property value with the data binding value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Add
|
Conditional,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10,49 +10,40 @@ namespace Artemis.Core
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public class DataBindingModifier<TLayerProperty, TProperty> : IDataBindingModifier
|
public class DataBindingModifier<TLayerProperty, TProperty> : IDataBindingModifier
|
||||||
{
|
{
|
||||||
private DataBinding<TLayerProperty, TProperty> _dataBinding;
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the <see cref="DataBindingModifier{TLayerProperty,TProperty}" /> class
|
/// Creates a new instance of the <see cref="DataBindingModifier{TLayerProperty,TProperty}" /> class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dataBinding">The data binding the modifier is to be applied to</param>
|
/// <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>
|
/// <param name="parameterType">The type of the parameter, can either be dynamic (based on a data model value) or static</param>
|
||||||
public DataBindingModifier(DataBinding<TLayerProperty, TProperty> dataBinding, ProfileRightSideType parameterType)
|
public DataBindingModifier(DirectDataBinding<TLayerProperty, TProperty> directDataBinding, ProfileRightSideType parameterType)
|
||||||
{
|
{
|
||||||
_dataBinding = dataBinding ?? throw new ArgumentNullException(nameof(dataBinding));
|
DirectDataBinding = directDataBinding ?? throw new ArgumentNullException(nameof(directDataBinding));
|
||||||
ParameterType = parameterType;
|
ParameterType = parameterType;
|
||||||
Entity = new DataBindingModifierEntity();
|
Entity = new DataBindingModifierEntity();
|
||||||
Initialize();
|
Initialize();
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal DataBindingModifier(DataBinding<TLayerProperty, TProperty> dataBinding, DataBindingModifierEntity entity)
|
internal DataBindingModifier(DirectDataBinding<TLayerProperty, TProperty> directDataBinding, DataBindingModifierEntity entity)
|
||||||
{
|
{
|
||||||
_dataBinding = dataBinding;
|
DirectDataBinding = directDataBinding ?? throw new ArgumentNullException(nameof(directDataBinding));
|
||||||
Entity = entity;
|
Entity = entity;
|
||||||
Load();
|
Load();
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the data binding this modifier is applied to
|
|
||||||
/// </summary>
|
|
||||||
public DataBinding<TLayerProperty, TProperty> DataBinding
|
|
||||||
{
|
|
||||||
get => _dataBinding;
|
|
||||||
internal set
|
|
||||||
{
|
|
||||||
_dataBinding = value;
|
|
||||||
CreateExpression();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the type of modifier that is being applied
|
/// Gets the type of modifier that is being applied
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DataBindingModifierType ModifierType { get; private set; }
|
public DataBindingModifierType ModifierType { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the direct data binding this modifier is applied to
|
||||||
|
/// </summary>
|
||||||
|
public DirectDataBinding<TLayerProperty, TProperty> DirectDataBinding { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the type of the parameter, can either be dynamic (based on a data model value) or static
|
/// Gets the type of the parameter, can either be dynamic (based on a data model value) or static
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -93,8 +84,8 @@ namespace Artemis.Core
|
|||||||
if (_disposed)
|
if (_disposed)
|
||||||
throw new ObjectDisposedException("DataBindingModifier");
|
throw new ObjectDisposedException("DataBindingModifier");
|
||||||
|
|
||||||
if (!DataBinding.Entity.Modifiers.Contains(Entity))
|
if (!DirectDataBinding.Entity.Modifiers.Contains(Entity))
|
||||||
DataBinding.Entity.Modifiers.Add(Entity);
|
DirectDataBinding.Entity.Modifiers.Add(Entity);
|
||||||
|
|
||||||
// Modifier
|
// Modifier
|
||||||
if (ModifierType != null)
|
if (ModifierType != null)
|
||||||
@ -177,7 +168,7 @@ namespace Artemis.Core
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetType = DataBinding.GetTargetType();
|
var targetType = DirectDataBinding.DataBinding.GetTargetType();
|
||||||
if (!modifierType.SupportsType(targetType))
|
if (!modifierType.SupportsType(targetType))
|
||||||
{
|
{
|
||||||
throw new ArtemisCoreException($"Cannot apply modifier type {modifierType.GetType().Name} to this modifier because " +
|
throw new ArtemisCoreException($"Cannot apply modifier type {modifierType.GetType().Name} to this modifier because " +
|
||||||
@ -229,7 +220,7 @@ namespace Artemis.Core
|
|||||||
ParameterDataModel = null;
|
ParameterDataModel = null;
|
||||||
ParameterPropertyPath = null;
|
ParameterPropertyPath = null;
|
||||||
|
|
||||||
var targetType = DataBinding.GetTargetType();
|
var targetType = DirectDataBinding.DataBinding.GetTargetType();
|
||||||
|
|
||||||
// If not null ensure the types match and if not, convert it
|
// If not null ensure the types match and if not, convert it
|
||||||
if (staticValue != null && staticValue.GetType() == targetType)
|
if (staticValue != null && staticValue.GetType() == targetType)
|
||||||
@ -271,7 +262,7 @@ namespace Artemis.Core
|
|||||||
else if (ParameterType == ProfileRightSideType.Static && Entity.ParameterStaticValue != null && ParameterStaticValue == null)
|
else if (ParameterType == ProfileRightSideType.Static && Entity.ParameterStaticValue != null && ParameterStaticValue == null)
|
||||||
{
|
{
|
||||||
// Use the target type so JSON.NET has a better idea what to do
|
// Use the target type so JSON.NET has a better idea what to do
|
||||||
var targetType = DataBinding.GetTargetType();
|
var targetType = DirectDataBinding.DataBinding.GetTargetType();
|
||||||
object staticValue;
|
object staticValue;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -293,7 +284,7 @@ namespace Artemis.Core
|
|||||||
{
|
{
|
||||||
CompiledParameterAccessor = null;
|
CompiledParameterAccessor = null;
|
||||||
|
|
||||||
if (ModifierType == null || DataBinding == null)
|
if (ModifierType == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ParameterType == ProfileRightSideType.Dynamic && ModifierType.SupportsParameter)
|
if (ParameterType == ProfileRightSideType.Dynamic && ModifierType.SupportsParameter)
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
using Artemis.Storage.Entities.Profile.DataBindings;
|
||||||
|
|
||||||
|
namespace Artemis.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a data binding mode that applies a value depending on conditions
|
||||||
|
/// </summary>
|
||||||
|
public class ConditionalDataBinding<TLayerProperty, TProperty> : IDataBindingMode<TLayerProperty, TProperty>
|
||||||
|
{
|
||||||
|
internal ConditionalDataBinding(DataBinding<TLayerProperty, TProperty> dataBinding, ConditionalDataBindingEntity entity)
|
||||||
|
{
|
||||||
|
DataBinding = dataBinding;
|
||||||
|
Entity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public DataBinding<TLayerProperty, TProperty> DataBinding { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public TProperty GetValue(TProperty baseValue)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal ConditionalDataBindingEntity Entity { get; }
|
||||||
|
|
||||||
|
#region Storage
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Load()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,255 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using Artemis.Core.DataModelExpansions;
|
||||||
|
using Artemis.Storage.Entities.Profile.DataBindings;
|
||||||
|
|
||||||
|
namespace Artemis.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a data binding mode that directly applies a data model value to a data binding
|
||||||
|
/// </summary>
|
||||||
|
public class DirectDataBinding<TLayerProperty, TProperty> : IDataBindingMode<TLayerProperty, TProperty>
|
||||||
|
{
|
||||||
|
private readonly List<DataBindingModifier<TLayerProperty, TProperty>> _modifiers = new List<DataBindingModifier<TLayerProperty, TProperty>>();
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
internal DirectDataBinding(DataBinding<TLayerProperty, TProperty> dataBinding, DirectDataBindingEntity entity)
|
||||||
|
{
|
||||||
|
DataBinding = dataBinding;
|
||||||
|
Entity = entity;
|
||||||
|
|
||||||
|
Initialize();
|
||||||
|
Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public DataBinding<TLayerProperty, TProperty> DataBinding { get; }
|
||||||
|
|
||||||
|
internal DirectDataBindingEntity Entity { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the currently used instance of the data model that contains the source of the data binding
|
||||||
|
/// </summary>
|
||||||
|
public DataModel SourceDataModel { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path of the source property in the <see cref="SourceDataModel" />
|
||||||
|
/// </summary>
|
||||||
|
public string SourcePropertyPath { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of modifiers applied to this data binding
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<DataBindingModifier<TLayerProperty, TProperty>> Modifiers => _modifiers.AsReadOnly();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the compiled function that gets the current value of the data binding target
|
||||||
|
/// </summary>
|
||||||
|
public Func<DataModel, object> CompiledTargetAccessor { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public TProperty GetValue(TProperty baseValue)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("DataBinding");
|
||||||
|
|
||||||
|
if (CompiledTargetAccessor == null)
|
||||||
|
return baseValue;
|
||||||
|
|
||||||
|
var dataBindingValue = CompiledTargetAccessor(SourceDataModel);
|
||||||
|
foreach (var dataBindingModifier in Modifiers)
|
||||||
|
dataBindingValue = dataBindingModifier.Apply(dataBindingValue);
|
||||||
|
|
||||||
|
return DataBinding.Converter.ConvertFromObject(dataBindingValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDisposable
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_disposed = true;
|
||||||
|
|
||||||
|
foreach (var dataBindingModifier in Modifiers)
|
||||||
|
dataBindingModifier.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Storage
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Load()
|
||||||
|
{
|
||||||
|
// Data model is done during Initialize
|
||||||
|
|
||||||
|
// Modifiers
|
||||||
|
foreach (var dataBindingModifierEntity in Entity.Modifiers)
|
||||||
|
_modifiers.Add(new DataBindingModifier<TLayerProperty, TProperty>(this, dataBindingModifierEntity));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
// Data model
|
||||||
|
if (SourceDataModel != null)
|
||||||
|
{
|
||||||
|
Entity.SourceDataModelGuid = SourceDataModel.PluginInfo.Guid;
|
||||||
|
Entity.SourcePropertyPath = SourcePropertyPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modifiers
|
||||||
|
Entity.Modifiers.Clear();
|
||||||
|
foreach (var dataBindingModifier in Modifiers)
|
||||||
|
dataBindingModifier.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Initialization
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
|
{
|
||||||
|
DataModelStore.DataModelAdded += DataModelStoreOnDataModelAdded;
|
||||||
|
DataModelStore.DataModelRemoved += DataModelStoreOnDataModelRemoved;
|
||||||
|
|
||||||
|
// Source
|
||||||
|
if (Entity.SourceDataModelGuid != null && SourceDataModel == null)
|
||||||
|
{
|
||||||
|
var dataModel = DataModelStore.Get(Entity.SourceDataModelGuid.Value)?.DataModel;
|
||||||
|
if (dataModel != null && dataModel.ContainsPath(Entity.SourcePropertyPath))
|
||||||
|
UpdateSource(dataModel, Entity.SourcePropertyPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateExpression()
|
||||||
|
{
|
||||||
|
var listType = SourceDataModel.GetListTypeInPath(SourcePropertyPath);
|
||||||
|
if (listType != null)
|
||||||
|
throw new ArtemisCoreException($"Cannot create a regular accessor at path {SourcePropertyPath} because the path contains a list");
|
||||||
|
|
||||||
|
var parameter = Expression.Parameter(typeof(DataModel), "targetDataModel");
|
||||||
|
var accessor = SourcePropertyPath.Split('.').Aggregate<string, Expression>(
|
||||||
|
Expression.Convert(parameter, SourceDataModel.GetType()), // Cast to the appropriate type
|
||||||
|
Expression.Property
|
||||||
|
);
|
||||||
|
|
||||||
|
var returnValue = Expression.Convert(accessor, typeof(object));
|
||||||
|
|
||||||
|
var lambda = Expression.Lambda<Func<DataModel, object>>(returnValue, parameter);
|
||||||
|
CompiledTargetAccessor = lambda.Compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Source
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the type of the source property of this data binding
|
||||||
|
/// </summary>
|
||||||
|
public Type GetSourceType()
|
||||||
|
{
|
||||||
|
return SourceDataModel?.GetTypeAtPath(SourcePropertyPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the source of the data binding and re-compiles the expression
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataModel">The data model of the source</param>
|
||||||
|
/// <param name="path">The path pointing to the source inside the data model</param>
|
||||||
|
public void UpdateSource(DataModel dataModel, string path)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("DataBinding");
|
||||||
|
|
||||||
|
if (dataModel != null && path == null)
|
||||||
|
throw new ArtemisCoreException("If a data model is provided, a path is also required");
|
||||||
|
if (dataModel == null && path != null)
|
||||||
|
throw new ArtemisCoreException("If path is provided, a data model is also required");
|
||||||
|
|
||||||
|
if (dataModel != null)
|
||||||
|
{
|
||||||
|
if (!dataModel.ContainsPath(path))
|
||||||
|
throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{path}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceDataModel = dataModel;
|
||||||
|
SourcePropertyPath = path;
|
||||||
|
CreateExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Modifiers
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a modifier to the data binding's <see cref="Modifiers" /> collection
|
||||||
|
/// </summary>
|
||||||
|
public DataBindingModifier<TLayerProperty, TProperty> AddModifier(ProfileRightSideType type)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("DataBinding");
|
||||||
|
|
||||||
|
var modifier = new DataBindingModifier<TLayerProperty, TProperty>(this, type);
|
||||||
|
_modifiers.Add(modifier);
|
||||||
|
OnModifiersUpdated();
|
||||||
|
|
||||||
|
return modifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a modifier from the data binding's <see cref="Modifiers" /> collection and disposes it
|
||||||
|
/// </summary>
|
||||||
|
public void RemoveModifier(DataBindingModifier<TLayerProperty, TProperty> modifier)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("DataBinding");
|
||||||
|
|
||||||
|
if (_modifiers.Contains(modifier))
|
||||||
|
{
|
||||||
|
_modifiers.Remove(modifier);
|
||||||
|
modifier.Dispose();
|
||||||
|
|
||||||
|
OnModifiersUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Event handlers
|
||||||
|
|
||||||
|
private void DataModelStoreOnDataModelAdded(object sender, DataModelStoreEvent e)
|
||||||
|
{
|
||||||
|
var dataModel = e.Registration.DataModel;
|
||||||
|
if (dataModel.PluginInfo.Guid == Entity.SourceDataModelGuid && dataModel.ContainsPath(Entity.SourcePropertyPath))
|
||||||
|
UpdateSource(dataModel, Entity.SourcePropertyPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e)
|
||||||
|
{
|
||||||
|
if (SourceDataModel != e.Registration.DataModel)
|
||||||
|
return;
|
||||||
|
SourceDataModel = null;
|
||||||
|
CompiledTargetAccessor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a modifier is added or removed
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler ModifiersUpdated;
|
||||||
|
|
||||||
|
protected virtual void OnModifiersUpdated()
|
||||||
|
{
|
||||||
|
ModifiersUpdated?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a data binding mode
|
||||||
|
/// </summary>
|
||||||
|
public interface IDataBindingMode<TLayerProperty, TProperty> : IStorageModel, IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data binding this mode is applied to
|
||||||
|
/// </summary>
|
||||||
|
DataBinding<TLayerProperty, TProperty> DataBinding { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current value of the data binding
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseValue">The base value of the property the data binding is applied to</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TProperty GetValue(TProperty baseValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -738,7 +738,7 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
private void LayerBrushStoreOnLayerBrushAdded(object sender, LayerBrushStoreEvent e)
|
private void LayerBrushStoreOnLayerBrushAdded(object sender, LayerBrushStoreEvent e)
|
||||||
{
|
{
|
||||||
if (LayerBrush != null)
|
if (LayerBrush != null || General.BrushReference?.CurrentValue == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var current = General.BrushReference.CurrentValue;
|
var current = General.BrushReference.CurrentValue;
|
||||||
|
|||||||
@ -7,8 +7,8 @@ namespace Artemis.Core
|
|||||||
{
|
{
|
||||||
internal SKSizeLayerProperty()
|
internal SKSizeLayerProperty()
|
||||||
{
|
{
|
||||||
RegisterDataBindingProperty(size => size.Width, new FloatDataBindingConverter<SKSize>());
|
|
||||||
RegisterDataBindingProperty(size => size.Height, new FloatDataBindingConverter<SKSize>());
|
RegisterDataBindingProperty(size => size.Height, new FloatDataBindingConverter<SKSize>());
|
||||||
|
RegisterDataBindingProperty(size => size.Width, new FloatDataBindingConverter<SKSize>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Entities.Profile.DataBindings
|
||||||
|
{
|
||||||
|
public class ConditionalDataBindingEntity : IDataBindingModeEntity
|
||||||
|
{
|
||||||
|
public ConditionalDataBindingEntity()
|
||||||
|
{
|
||||||
|
Values = new List<DataBindingConditionValueEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DataBindingConditionValueEntity> Values { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
using Artemis.Storage.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Entities.Profile.DataBindings
|
||||||
|
{
|
||||||
|
public class DataBindingConditionValueEntity
|
||||||
|
{
|
||||||
|
public string Value { get; set; }
|
||||||
|
public DisplayConditionGroupEntity RootGroup { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,23 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Profile.DataBindings
|
namespace Artemis.Storage.Entities.Profile.DataBindings
|
||||||
{
|
{
|
||||||
public class DataBindingEntity
|
public class DataBindingEntity
|
||||||
{
|
{
|
||||||
public DataBindingEntity()
|
|
||||||
{
|
|
||||||
Modifiers = new List<DataBindingModifierEntity>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string TargetExpression { get; set; }
|
public string TargetExpression { get; set; }
|
||||||
public Guid? SourceDataModelGuid { get; set; }
|
|
||||||
public string SourcePropertyPath { get; set; }
|
|
||||||
public int DataBindingMode { get; set; }
|
|
||||||
public TimeSpan EasingTime { get; set; }
|
public TimeSpan EasingTime { get; set; }
|
||||||
public int EasingFunction { get; set; }
|
public int EasingFunction { get; set; }
|
||||||
|
|
||||||
public List<DataBindingModifierEntity> Modifiers { get; set; }
|
public IDataBindingModeEntity DataBindingMode { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Entities.Profile.DataBindings
|
||||||
|
{
|
||||||
|
public class DirectDataBindingEntity : IDataBindingModeEntity
|
||||||
|
{
|
||||||
|
public DirectDataBindingEntity()
|
||||||
|
{
|
||||||
|
Modifiers = new List<DataBindingModifierEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid? SourceDataModelGuid { get; set; }
|
||||||
|
public string SourcePropertyPath { get; set; }
|
||||||
|
|
||||||
|
public List<DataBindingModifierEntity> Modifiers { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace Artemis.Storage.Entities.Profile.DataBindings
|
||||||
|
{
|
||||||
|
public interface IDataBindingModeEntity
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using System.Linq;
|
|
||||||
using Artemis.Storage.Entities.Profile;
|
|
||||||
using Artemis.Storage.Migrations.Interfaces;
|
using Artemis.Storage.Migrations.Interfaces;
|
||||||
using LiteDB;
|
using LiteDB;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Artemis.Storage.Migrations
|
namespace Artemis.Storage.Migrations
|
||||||
{
|
{
|
||||||
|
|||||||
31
src/Artemis.Storage/Migrations/M5DataBindingTypes.cs
Normal file
31
src/Artemis.Storage/Migrations/M5DataBindingTypes.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using Artemis.Storage.Migrations.Interfaces;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrations
|
||||||
|
{
|
||||||
|
public class M5DataBindingTypes : IStorageMigration
|
||||||
|
{
|
||||||
|
public int UserVersion => 5;
|
||||||
|
|
||||||
|
public void Apply(LiteRepository repository)
|
||||||
|
{
|
||||||
|
var collection = repository.Database.GetCollection("ProfileEntity");
|
||||||
|
foreach (var bsonDocument in collection.FindAll())
|
||||||
|
{
|
||||||
|
foreach (var bsonLayer in bsonDocument["Layers"].AsArray)
|
||||||
|
{
|
||||||
|
foreach (var bsonPropertyEntity in bsonLayer["PropertyEntities"].AsArray)
|
||||||
|
bsonPropertyEntity["DataBindingEntities"].AsArray.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var bsonLayer in bsonDocument["Folders"].AsArray)
|
||||||
|
{
|
||||||
|
foreach (var bsonPropertyEntity in bsonLayer["PropertyEntities"].AsArray)
|
||||||
|
bsonPropertyEntity["DataBindingEntities"].AsArray.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
collection.Update(bsonDocument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,8 @@ using Artemis.UI.Screens.ProfileEditor;
|
|||||||
using Artemis.UI.Screens.ProfileEditor.DisplayConditions;
|
using Artemis.UI.Screens.ProfileEditor.DisplayConditions;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties;
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings;
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings;
|
||||||
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.ConditionalDataBinding;
|
||||||
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.LayerEffects;
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.LayerEffects;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree;
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree;
|
||||||
@ -87,6 +89,8 @@ namespace Artemis.UI.Ninject.Factories
|
|||||||
{
|
{
|
||||||
IDataBindingViewModel DataBindingViewModel(IDataBindingRegistration registration);
|
IDataBindingViewModel DataBindingViewModel(IDataBindingRegistration registration);
|
||||||
DataBindingModifierViewModel<TLayerProperty, TProperty> DataBindingModifierViewModel<TLayerProperty, TProperty>(DataBindingModifier<TLayerProperty, TProperty> modifier);
|
DataBindingModifierViewModel<TLayerProperty, TProperty> DataBindingModifierViewModel<TLayerProperty, TProperty>(DataBindingModifier<TLayerProperty, TProperty> modifier);
|
||||||
|
DirectDataBindingModeViewModel<TLayerProperty, TProperty> DirectDataBindingModeViewModel<TLayerProperty, TProperty>(DirectDataBinding<TLayerProperty, TProperty> directDataBinding);
|
||||||
|
ConditionalDataBindingModeViewModel<TLayerProperty, TProperty> ConditionalDataBindingModeViewModel<TLayerProperty, TProperty>(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IPropertyVmFactory
|
public interface IPropertyVmFactory
|
||||||
|
|||||||
@ -31,6 +31,29 @@
|
|||||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Background="{StaticResource MaterialDesignCardBackground}">
|
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Background="{StaticResource MaterialDesignCardBackground}">
|
||||||
<ContentControl s:View.Model="{Binding ActiveItem}" />
|
<ContentControl s:View.Model="{Binding ActiveItem}" />
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
|
<materialDesign:Card
|
||||||
|
Visibility="{Binding DisplayStartHint, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Background="{DynamicResource PrimaryHueDarkBrush}"
|
||||||
|
Foreground="{DynamicResource PrimaryHueDarkForegroundBrush}"
|
||||||
|
Margin="5 30 5 0"
|
||||||
|
Padding="8"
|
||||||
|
Width="315"
|
||||||
|
HorizontalAlignment="Left">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<materialDesign:PackIcon Kind="Redo" Margin="0 0 5 0">
|
||||||
|
<materialDesign:PackIcon.RenderTransform>
|
||||||
|
<RotateTransform Angle="225" CenterX="8" CenterY="8" />
|
||||||
|
</materialDesign:PackIcon.RenderTransform>
|
||||||
|
</materialDesign:PackIcon>
|
||||||
|
<TextBlock Grid.Column="1" VerticalAlignment="Center">Click the plus icon to start using display conditions!</TextBlock>
|
||||||
|
</Grid>
|
||||||
|
</materialDesign:Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid Grid.Row="3">
|
<Grid Grid.Row="3">
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.ConditionalDataBinding.ConditionalDataBindingModeView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
<Grid>
|
||||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Margin="16">
|
||||||
|
<materialDesign:PackIcon Kind="Crane" Width="60" Height="60" HorizontalAlignment="Center" />
|
||||||
|
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 25">
|
||||||
|
Conditional data bindings not yet implemented
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center">
|
||||||
|
This is where you'd provide values and their conditions.. :>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
using Artemis.Core;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.ConditionalDataBinding
|
||||||
|
{
|
||||||
|
public class ConditionalDataBindingModeViewModel<TLayerProperty, TProperty> : Screen, IDataBindingModeViewModel
|
||||||
|
{
|
||||||
|
public ConditionalDataBindingModeViewModel(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding)
|
||||||
|
{
|
||||||
|
ConditionalDataBinding = conditionalDataBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConditionalDataBinding<TLayerProperty, TProperty> ConditionalDataBinding { get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetTestValue()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,152 +17,112 @@
|
|||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
<Grid Margin="10 0">
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="0.75*" />
|
<ColumnDefinition Width="0.75*" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid Margin="0 5 5 0">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="48" />
|
|
||||||
<RowDefinition Height="48" />
|
|
||||||
<RowDefinition Height="48" />
|
|
||||||
<RowDefinition Height="48" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<StackPanel Grid.Row="0" Margin="-3 0 0 0">
|
<materialDesign:Card Grid.Column="0"
|
||||||
<Label FontSize="10" Foreground="{StaticResource MaterialDesignNavigationItemSubheader}" Margin="0 0 0 2">Source</Label>
|
UniformCornerRadius="0"
|
||||||
<ContentControl s:View.Model="{Binding TargetSelectionViewModel}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
materialDesign:ShadowAssist.ShadowDepth="Depth3"
|
||||||
</StackPanel>
|
materialDesign:ShadowAssist.ShadowEdges="Right"
|
||||||
|
Background="{DynamicResource MaterialDesignPaper}"
|
||||||
|
Panel.ZIndex="2">
|
||||||
|
<Grid Margin="10 5" >
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="48" />
|
||||||
|
<RowDefinition Height="48" />
|
||||||
|
<RowDefinition Height="48" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<ComboBox Grid.Row="1"
|
<ComboBox Grid.Row="0"
|
||||||
Style="{StaticResource MaterialDesignFloatingHintComboBox}"
|
Style="{StaticResource MaterialDesignFloatingHintComboBox}"
|
||||||
materialDesign:HintAssist.Hint="Data binding mode"
|
materialDesign:HintAssist.Hint="Data binding mode"
|
||||||
MinWidth="128"
|
MinWidth="128"
|
||||||
SelectedValue="{Binding SelectedDataBindingMode}" ItemsSource="{Binding DataBindingModes}" SelectedValuePath="Value" DisplayMemberPath="Description" >
|
SelectedValue="{Binding SelectedDataBindingMode}"
|
||||||
</ComboBox>
|
ItemsSource="{Binding DataBindingModes}"
|
||||||
|
SelectedValuePath="Value"
|
||||||
|
DisplayMemberPath="Description" >
|
||||||
|
</ComboBox>
|
||||||
|
|
||||||
<StackPanel Grid.Row="2">
|
<StackPanel Grid.Row="1">
|
||||||
<TextBox Style="{StaticResource MaterialDesignFloatingHintTextBox}"
|
<TextBox Style="{StaticResource MaterialDesignFloatingHintTextBox}"
|
||||||
Text="{Binding EasingTime}"
|
Text="{Binding EasingTime}"
|
||||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||||
materialDesign:TextFieldAssist.SuffixText="ms"
|
materialDesign:TextFieldAssist.SuffixText="ms"
|
||||||
materialDesign:HintAssist.Hint="Easing time"
|
materialDesign:HintAssist.Hint="Easing time"
|
||||||
IsEnabled="{Binding IsDataBindingEnabled}" />
|
IsEnabled="{Binding IsDataBindingEnabled}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<ComboBox Grid.Row="3"
|
<ComboBox Grid.Row="2"
|
||||||
Style="{StaticResource MaterialDesignFloatingHintComboBox}"
|
Style="{StaticResource MaterialDesignFloatingHintComboBox}"
|
||||||
materialDesign:HintAssist.Hint="Easing type"
|
materialDesign:HintAssist.Hint="Easing type"
|
||||||
MinWidth="128"
|
MinWidth="128"
|
||||||
IsEnabled="{Binding IsEasingTimeEnabled}"
|
IsEnabled="{Binding IsEasingTimeEnabled}"
|
||||||
SelectedItem="{Binding SelectedEasingViewModel}"
|
SelectedItem="{Binding SelectedEasingViewModel}"
|
||||||
ItemsSource="{Binding EasingViewModels}">
|
ItemsSource="{Binding EasingViewModels}">
|
||||||
<ComboBox.ItemsPanel>
|
<ComboBox.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<VirtualizingStackPanel />
|
<VirtualizingStackPanel />
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</ComboBox.ItemsPanel>
|
</ComboBox.ItemsPanel>
|
||||||
<ComboBox.ItemTemplate>
|
<ComboBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<Polyline Stroke="{DynamicResource MaterialDesignBody}"
|
<Polyline Stroke="{DynamicResource MaterialDesignBody}"
|
||||||
StrokeThickness="1"
|
StrokeThickness="1"
|
||||||
Points="{Binding EasingPoints}"
|
Points="{Binding EasingPoints}"
|
||||||
Stretch="Uniform"
|
Stretch="Uniform"
|
||||||
Width="14"
|
Width="14"
|
||||||
Height="14"
|
Height="14"
|
||||||
Margin="0 0 10 0" />
|
Margin="0 0 10 0" />
|
||||||
<TextBlock Text="{Binding Description}" />
|
<TextBlock Text="{Binding Description}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
|
||||||
</ComboBox.ItemTemplate>
|
|
||||||
</ComboBox>
|
|
||||||
|
|
||||||
<materialDesign:Card Grid.Row="4" Grid.ColumnSpan="2" Margin="0 5 0 0">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<TextBlock Grid.Row="0" Margin="10 10 4 0">
|
|
||||||
Test result
|
|
||||||
</TextBlock>
|
|
||||||
<Separator Grid.Row="1" Style="{StaticResource MaterialDesignLightSeparator}" Margin="0" />
|
|
||||||
<Grid Grid.Row="2" Margin="10 4 10 10">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition />
|
|
||||||
<ColumnDefinition />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<TextBlock Margin="0 2">Input</TextBlock>
|
|
||||||
<TextBlock Grid.Row="0" Grid.Column="1" Margin="0 2" FontFamily="Consolas" Text="{Binding TestInputValue}" />
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0 2">Output</TextBlock>
|
|
||||||
<TextBlock Grid.Row="1" Grid.Column="1" Margin="0 2" FontFamily="Consolas" Text="{Binding TestResultValue}" />
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</materialDesign:Card>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid Grid.Column="1">
|
|
||||||
<Grid Margin="5 26 0 0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition />
|
|
||||||
<ColumnDefinition />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<Button Style="{StaticResource MaterialDesignFlatMidBgButton}"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
FontSize="12"
|
|
||||||
Padding="6 4"
|
|
||||||
Height="22"
|
|
||||||
IsEnabled="{Binding CanAddModifier}"
|
|
||||||
Command="{s:Action AddModifier}">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<materialDesign:PackIcon Margin="0 -1 4 0" Kind="Plus" />
|
|
||||||
<TextBlock>
|
|
||||||
Add modifier
|
|
||||||
</TextBlock>
|
|
||||||
</StackPanel>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<CheckBox Grid.Row="0"
|
|
||||||
Grid.Column="1"
|
|
||||||
Style="{StaticResource MaterialDesignCheckBox}"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
IsChecked="{Binding IsDataBindingEnabled}">
|
|
||||||
Enable data binding
|
|
||||||
</CheckBox>
|
|
||||||
|
|
||||||
<ListBox Grid.Row="1"
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.ColumnSpan="2"
|
|
||||||
ItemsSource="{Binding ModifierViewModels}"
|
|
||||||
materialDesign:RippleAssist.IsDisabled="True"
|
|
||||||
dd:DragDrop.IsDragSource="True"
|
|
||||||
dd:DragDrop.IsDropTarget="True"
|
|
||||||
dd:DragDrop.UseDefaultDragAdorner="True"
|
|
||||||
dd:DragDrop.DropHandler="{Binding}"
|
|
||||||
HorizontalContentAlignment="Stretch">
|
|
||||||
<ListBox.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ComboBox.ItemTemplate>
|
||||||
</ListBox>
|
</ComboBox>
|
||||||
|
|
||||||
|
<materialDesign:Card Grid.Row="3" Grid.ColumnSpan="2" Margin="0 5 0 0">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock Grid.Row="0" Margin="10 10 4 0">
|
||||||
|
Test result
|
||||||
|
</TextBlock>
|
||||||
|
<Separator Grid.Row="1" Style="{StaticResource MaterialDesignLightSeparator}" Margin="0" />
|
||||||
|
<Grid Grid.Row="2" Margin="10 4 10 10">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock Margin="0 2">Input</TextBlock>
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="1" Margin="0 2" FontFamily="Consolas" Text="{Binding TestInputValue}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0 2">Output</TextBlock>
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="1" Margin="0 2" FontFamily="Consolas" Text="{Binding TestResultValue}" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</materialDesign:Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</materialDesign:Card>
|
||||||
|
|
||||||
|
<materialDesign:Card Grid.Column="1" UniformCornerRadius="0" Background="{DynamicResource MaterialDesignToolBarBackground}" Panel.ZIndex="1">
|
||||||
|
<Grid Margin="10 5">
|
||||||
|
<ContentControl s:View.Model="{Binding ActiveItem, IsAsync=True}"
|
||||||
|
VerticalContentAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
IsTabStop="False"/>
|
||||||
|
</Grid>
|
||||||
|
</materialDesign:Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -4,38 +4,32 @@ using Artemis.Core;
|
|||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Input;
|
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Ninject.Planning.Targets;
|
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||||
{
|
{
|
||||||
public class DataBindingViewModel<TLayerProperty, TProperty> : Screen, IDataBindingViewModel
|
public class DataBindingViewModel<TLayerProperty, TProperty> : Conductor<IDataBindingModeViewModel>, IDataBindingViewModel
|
||||||
{
|
{
|
||||||
private readonly IDataBindingsVmFactory _dataBindingsVmFactory;
|
private readonly IDataBindingsVmFactory _dataBindingsVmFactory;
|
||||||
private readonly IDataModelUIService _dataModelUIService;
|
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private DataBinding<TLayerProperty, TProperty> _dataBinding;
|
private DataBinding<TLayerProperty, TProperty> _dataBinding;
|
||||||
private int _easingTime;
|
private int _easingTime;
|
||||||
private bool _isDataBindingEnabled;
|
|
||||||
private bool _isEasingTimeEnabled;
|
private bool _isEasingTimeEnabled;
|
||||||
private DataBindingMode _selectedDataBindingMode;
|
private DataBindingModeType _selectedDataBindingMode;
|
||||||
private TimelineEasingViewModel _selectedEasingViewModel;
|
private TimelineEasingViewModel _selectedEasingViewModel;
|
||||||
private DataModelDynamicViewModel _targetSelectionViewModel;
|
|
||||||
private TProperty _testInputValue;
|
private TProperty _testInputValue;
|
||||||
private TProperty _testResultValue;
|
private TProperty _testResultValue;
|
||||||
private bool _updating;
|
private bool _updating;
|
||||||
private bool _canAddModifier;
|
private bool _isDataBindingEnabled;
|
||||||
|
|
||||||
public DataBindingViewModel(DataBindingRegistration<TLayerProperty, TProperty> registration,
|
public DataBindingViewModel(DataBindingRegistration<TLayerProperty, TProperty> registration,
|
||||||
IProfileEditorService profileEditorService,
|
IProfileEditorService profileEditorService,
|
||||||
IDataModelUIService dataModelUIService,
|
|
||||||
IDataBindingsVmFactory dataBindingsVmFactory)
|
IDataBindingsVmFactory dataBindingsVmFactory)
|
||||||
{
|
{
|
||||||
Registration = registration;
|
Registration = registration;
|
||||||
_profileEditorService = profileEditorService;
|
_profileEditorService = profileEditorService;
|
||||||
_dataModelUIService = dataModelUIService;
|
|
||||||
_dataBindingsVmFactory = dataBindingsVmFactory;
|
_dataBindingsVmFactory = dataBindingsVmFactory;
|
||||||
|
|
||||||
if (Registration.Member != null)
|
if (Registration.Member != null)
|
||||||
@ -43,15 +37,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
else
|
else
|
||||||
DisplayName = Registration.LayerProperty.PropertyDescription.Name.ToUpper();
|
DisplayName = Registration.LayerProperty.PropertyDescription.Name.ToUpper();
|
||||||
|
|
||||||
DataBindingModes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(DataBindingMode)));
|
DataBindingModes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(DataBindingModeType)));
|
||||||
EasingViewModels = new BindableCollection<TimelineEasingViewModel>();
|
EasingViewModels = new BindableCollection<TimelineEasingViewModel>();
|
||||||
ModifierViewModels = new BindableCollection<DataBindingModifierViewModel<TLayerProperty, TProperty>>();
|
|
||||||
|
|
||||||
DataBinding = Registration.DataBinding;
|
DataBinding = Registration.DataBinding;
|
||||||
if (DataBinding != null)
|
|
||||||
DataBinding.ModifiersUpdated += DataBindingOnModifiersUpdated;
|
|
||||||
|
|
||||||
_isDataBindingEnabled = DataBinding != null;
|
|
||||||
|
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
@ -60,12 +49,21 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
|
|
||||||
public BindableCollection<ValueDescription> DataBindingModes { get; }
|
public BindableCollection<ValueDescription> DataBindingModes { get; }
|
||||||
public BindableCollection<TimelineEasingViewModel> EasingViewModels { get; }
|
public BindableCollection<TimelineEasingViewModel> EasingViewModels { get; }
|
||||||
public BindableCollection<DataBindingModifierViewModel<TLayerProperty, TProperty>> ModifierViewModels { get; }
|
|
||||||
|
|
||||||
public DataBindingMode SelectedDataBindingMode
|
public DataBindingModeType SelectedDataBindingMode
|
||||||
{
|
{
|
||||||
get => _selectedDataBindingMode;
|
get => _selectedDataBindingMode;
|
||||||
set => SetAndNotify(ref _selectedDataBindingMode, value);
|
set
|
||||||
|
{
|
||||||
|
if (!SetAndNotify(ref _selectedDataBindingMode, value)) return;
|
||||||
|
ApplyDataBindingMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDataBindingEnabled
|
||||||
|
{
|
||||||
|
get => _isDataBindingEnabled;
|
||||||
|
set => SetAndNotify(ref _isDataBindingEnabled, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimelineEasingViewModel SelectedEasingViewModel
|
public TimelineEasingViewModel SelectedEasingViewModel
|
||||||
@ -98,39 +96,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataModelDynamicViewModel TargetSelectionViewModel
|
|
||||||
{
|
|
||||||
get => _targetSelectionViewModel;
|
|
||||||
private set => SetAndNotify(ref _targetSelectionViewModel, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsDataBindingEnabled
|
|
||||||
{
|
|
||||||
get => _isDataBindingEnabled;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!SetAndNotify(ref _isDataBindingEnabled, value)) return;
|
|
||||||
if (value)
|
|
||||||
EnableDataBinding();
|
|
||||||
else
|
|
||||||
RemoveDataBinding();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanAddModifier
|
|
||||||
{
|
|
||||||
get => _canAddModifier;
|
|
||||||
private set => SetAndNotify(ref _canAddModifier, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DataBinding<TLayerProperty, TProperty> DataBinding
|
public DataBinding<TLayerProperty, TProperty> DataBinding
|
||||||
{
|
{
|
||||||
get => _dataBinding;
|
get => _dataBinding;
|
||||||
set
|
set => SetAndNotify(ref _dataBinding, value);
|
||||||
{
|
|
||||||
if (!SetAndNotify(ref _dataBinding, value)) return;
|
|
||||||
UpdateModifierViewModels();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TProperty TestInputValue
|
public TProperty TestInputValue
|
||||||
@ -145,79 +114,70 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
set => SetAndNotify(ref _testResultValue, value);
|
set => SetAndNotify(ref _testResultValue, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnableDataBinding()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (DataBinding != null)
|
_profileEditorService.ProfilePreviewUpdated -= ProfileEditorServiceOnProfilePreviewUpdated;
|
||||||
return;
|
|
||||||
|
|
||||||
DataBinding = Registration.LayerProperty.EnableDataBinding(Registration);
|
|
||||||
DataBinding.ModifiersUpdated += DataBindingOnModifiersUpdated;
|
|
||||||
Update();
|
|
||||||
|
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveDataBinding()
|
|
||||||
{
|
|
||||||
if (DataBinding == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var toDisable = DataBinding;
|
|
||||||
DataBinding = null;
|
|
||||||
Registration.LayerProperty.DisableDataBinding(toDisable);
|
|
||||||
toDisable.ModifiersUpdated -= DataBindingOnModifiersUpdated;
|
|
||||||
Update();
|
|
||||||
|
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddModifier()
|
|
||||||
{
|
|
||||||
if (DataBinding == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var modifier = new DataBindingModifier<TLayerProperty, TProperty>(DataBinding, ProfileRightSideType.Dynamic);
|
|
||||||
DataBinding.AddModifier(modifier);
|
|
||||||
|
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Initialize()
|
private void Initialize()
|
||||||
{
|
{
|
||||||
EasingViewModels.AddRange(Enum.GetValues(typeof(Easings.Functions)).Cast<Easings.Functions>().Select(v => new TimelineEasingViewModel(v, false)));
|
EasingViewModels.AddRange(Enum.GetValues(typeof(Easings.Functions)).Cast<Easings.Functions>().Select(v => new TimelineEasingViewModel(v, false)));
|
||||||
TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
|
||||||
TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected;
|
|
||||||
_profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated;
|
_profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated;
|
||||||
|
|
||||||
|
CreateDataBindingModeModeViewModel();
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateDataBindingModeModeViewModel()
|
||||||
|
{
|
||||||
|
if (DataBinding?.DataBindingMode == null)
|
||||||
|
{
|
||||||
|
ActiveItem = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (DataBinding.DataBindingMode)
|
||||||
|
{
|
||||||
|
case DirectDataBinding<TLayerProperty, TProperty> directDataBinding:
|
||||||
|
ActiveItem = _dataBindingsVmFactory.DirectDataBindingModeViewModel(directDataBinding);
|
||||||
|
break;
|
||||||
|
case ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding:
|
||||||
|
ActiveItem = _dataBindingsVmFactory.ConditionalDataBindingModeViewModel(conditionalDataBinding);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
if (_updating)
|
if (_updating)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CanAddModifier = IsDataBindingEnabled && DataBinding.SourceDataModel != null;
|
|
||||||
|
|
||||||
if (DataBinding == null)
|
if (DataBinding == null)
|
||||||
{
|
{
|
||||||
TargetSelectionViewModel.IsEnabled = false;
|
|
||||||
IsEasingTimeEnabled = false;
|
IsEasingTimeEnabled = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_updating = true;
|
_updating = true;
|
||||||
|
|
||||||
SelectedDataBindingMode = DataBinding.Mode;
|
IsDataBindingEnabled = ActiveItem != null;
|
||||||
EasingTime = (int) DataBinding.EasingTime.TotalMilliseconds;
|
EasingTime = (int) DataBinding.EasingTime.TotalMilliseconds;
|
||||||
SelectedEasingViewModel = EasingViewModels.First(vm => vm.EasingFunction == DataBinding.EasingFunction);
|
SelectedEasingViewModel = EasingViewModels.First(vm => vm.EasingFunction == DataBinding.EasingFunction);
|
||||||
IsEasingTimeEnabled = EasingTime > 0;
|
IsEasingTimeEnabled = EasingTime > 0;
|
||||||
|
switch (DataBinding.DataBindingMode)
|
||||||
|
{
|
||||||
|
case DirectDataBinding<TLayerProperty, TProperty> _:
|
||||||
|
SelectedDataBindingMode = DataBindingModeType.Direct;
|
||||||
|
break;
|
||||||
|
case ConditionalDataBinding<TLayerProperty, TProperty> _:
|
||||||
|
SelectedDataBindingMode = DataBindingModeType.Conditional;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SelectedDataBindingMode = DataBindingModeType.None;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
TargetSelectionViewModel.IsEnabled = true;
|
ActiveItem?.Update();
|
||||||
TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DataBinding.SourceDataModel, DataBinding.SourcePropertyPath);
|
|
||||||
TargetSelectionViewModel.FilterTypes = new[] {DataBinding.GetTargetType()};
|
|
||||||
|
|
||||||
UpdateModifierViewModels();
|
|
||||||
|
|
||||||
_updating = false;
|
_updating = false;
|
||||||
}
|
}
|
||||||
@ -229,7 +189,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
|
|
||||||
if (DataBinding != null)
|
if (DataBinding != null)
|
||||||
{
|
{
|
||||||
DataBinding.Mode = SelectedDataBindingMode;
|
|
||||||
DataBinding.EasingTime = TimeSpan.FromMilliseconds(EasingTime);
|
DataBinding.EasingTime = TimeSpan.FromMilliseconds(EasingTime);
|
||||||
DataBinding.EasingFunction = SelectedEasingViewModel?.EasingFunction ?? Easings.Functions.Linear;
|
DataBinding.EasingFunction = SelectedEasingViewModel?.EasingFunction ?? Easings.Functions.Linear;
|
||||||
}
|
}
|
||||||
@ -238,6 +197,27 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ApplyDataBindingMode()
|
||||||
|
{
|
||||||
|
if (_updating)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (DataBinding != null && SelectedDataBindingMode == DataBindingModeType.None)
|
||||||
|
{
|
||||||
|
RemoveDataBinding();
|
||||||
|
CreateDataBindingModeModeViewModel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DataBinding == null && SelectedDataBindingMode != DataBindingModeType.None)
|
||||||
|
EnableDataBinding();
|
||||||
|
|
||||||
|
DataBinding.ChangeDataBindingMode(SelectedDataBindingMode);
|
||||||
|
CreateDataBindingModeModeViewModel();
|
||||||
|
|
||||||
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateTestResult()
|
private void UpdateTestResult()
|
||||||
{
|
{
|
||||||
if (DataBinding == null)
|
if (DataBinding == null)
|
||||||
@ -247,10 +227,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentValue = TargetSelectionViewModel.SelectedPropertyViewModel?.GetCurrentValue();
|
var currentValue = ActiveItem?.GetTestValue() ?? default(TProperty);
|
||||||
if (currentValue == null)
|
|
||||||
currentValue = default(TProperty);
|
|
||||||
|
|
||||||
TestInputValue = Registration.Converter.ConvertFromObject(currentValue);
|
TestInputValue = Registration.Converter.ConvertFromObject(currentValue);
|
||||||
if (DataBinding != null)
|
if (DataBinding != null)
|
||||||
TestResultValue = DataBinding.GetValue(TestInputValue);
|
TestResultValue = DataBinding.GetValue(TestInputValue);
|
||||||
@ -258,49 +236,31 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
TestInputValue = default;
|
TestInputValue = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateModifierViewModels()
|
private void EnableDataBinding()
|
||||||
{
|
{
|
||||||
foreach (var dataBindingModifierViewModel in ModifierViewModels)
|
if (DataBinding != null)
|
||||||
dataBindingModifierViewModel.Dispose();
|
return;
|
||||||
ModifierViewModels.Clear();
|
|
||||||
|
|
||||||
|
DataBinding = Registration.LayerProperty.EnableDataBinding(Registration);
|
||||||
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveDataBinding()
|
||||||
|
{
|
||||||
if (DataBinding == null)
|
if (DataBinding == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var dataBindingModifier in DataBinding.Modifiers)
|
var toDisable = DataBinding;
|
||||||
ModifierViewModels.Add(_dataBindingsVmFactory.DataBindingModifierViewModel(dataBindingModifier));
|
DataBinding = null;
|
||||||
}
|
Registration.LayerProperty.DisableDataBinding(toDisable);
|
||||||
|
|
||||||
private void ProfileEditorServiceOnProfilePreviewUpdated(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
UpdateTestResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DataBindingOnModifiersUpdated(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
UpdateModifierViewModels();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TargetSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
|
|
||||||
{
|
|
||||||
DataBinding.UpdateSource(e.DataModelVisualizationViewModel.DataModel, e.DataModelVisualizationViewModel.PropertyPath);
|
|
||||||
Update();
|
Update();
|
||||||
|
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
private void ProfileEditorServiceOnProfilePreviewUpdated(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
_profileEditorService.ProfilePreviewUpdated -= ProfileEditorServiceOnProfilePreviewUpdated;
|
UpdateTestResult();
|
||||||
TargetSelectionViewModel.PropertySelected -= TargetSelectionViewModelOnPropertySelected;
|
|
||||||
TargetSelectionViewModel.Dispose();
|
|
||||||
if (DataBinding != null)
|
|
||||||
DataBinding.ModifiersUpdated -= DataBindingOnModifiersUpdated;
|
|
||||||
|
|
||||||
foreach (var dataBindingModifierViewModel in ModifierViewModels)
|
|
||||||
dataBindingModifierViewModel.Dispose();
|
|
||||||
ModifierViewModels.Clear();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DataBindingModifierView"
|
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding.DataBindingModifierView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
@ -1,17 +1,7 @@
|
|||||||
using System;
|
using System.Windows;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Navigation;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for DataBindingModifierView.xaml
|
/// Interaction logic for DataBindingModifierView.xaml
|
||||||
@ -7,7 +7,7 @@ using Artemis.UI.Shared.Input;
|
|||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding
|
||||||
{
|
{
|
||||||
public class DataBindingModifierViewModel<TLayerProperty, TProperty> : PropertyChangedBase, IDisposable
|
public class DataBindingModifierViewModel<TLayerProperty, TProperty> : PropertyChangedBase, IDisposable
|
||||||
{
|
{
|
||||||
@ -63,13 +63,13 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
|
|
||||||
public void Delete()
|
public void Delete()
|
||||||
{
|
{
|
||||||
Modifier.DataBinding.RemoveModifier(Modifier);
|
Modifier.DirectDataBinding.RemoveModifier(Modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SwapType()
|
public void SwapType()
|
||||||
{
|
{
|
||||||
if (Modifier.ParameterType == ProfileRightSideType.Dynamic)
|
if (Modifier.ParameterType == ProfileRightSideType.Dynamic)
|
||||||
Modifier.UpdateParameter(Modifier.DataBinding.GetSourceType().GetDefault());
|
Modifier.UpdateParameter(Modifier.DirectDataBinding.GetSourceType().GetDefault());
|
||||||
else
|
else
|
||||||
Modifier.UpdateParameter(null, null);
|
Modifier.UpdateParameter(null, null);
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
var sourceType = Modifier.DataBinding.GetSourceType();
|
var sourceType = Modifier.DirectDataBinding.GetSourceType();
|
||||||
if (sourceType == null)
|
if (sourceType == null)
|
||||||
throw new ArtemisUIException("Cannot use a data binding modifier VM for a data binding without a source");
|
throw new ArtemisUIException("Cannot use a data binding modifier VM for a data binding without a source");
|
||||||
|
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding.DirectDataBindingModeView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:dd="urn:gong-wpf-dragdrop"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
<Grid Margin="5 10 0 0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<ContentControl Grid.Row="0"
|
||||||
|
s:View.Model="{Binding TargetSelectionViewModel}"
|
||||||
|
VerticalContentAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
IsTabStop="False" />
|
||||||
|
|
||||||
|
<Button Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
Style="{StaticResource MaterialDesignFlatMidBgButton}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
FontSize="12"
|
||||||
|
Padding="6 4"
|
||||||
|
Height="22"
|
||||||
|
Command="{s:Action AddModifier}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Margin="0 -1 4 0" Kind="Plus" />
|
||||||
|
<TextBlock>
|
||||||
|
Add modifier
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<ListBox Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
ItemsSource="{Binding ModifierViewModels}"
|
||||||
|
materialDesign:RippleAssist.IsDisabled="True"
|
||||||
|
dd:DragDrop.IsDragSource="True"
|
||||||
|
dd:DragDrop.IsDropTarget="True"
|
||||||
|
dd:DragDrop.UseDefaultDragAdorner="True"
|
||||||
|
dd:DragDrop.DropHandler="{Binding}"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
Margin="0 5 0 0">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,118 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.UI.Ninject.Factories;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Input;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding
|
||||||
|
{
|
||||||
|
public class DirectDataBindingModeViewModel<TLayerProperty, TProperty> : Screen, IDataBindingModeViewModel
|
||||||
|
{
|
||||||
|
private readonly IDataBindingsVmFactory _dataBindingsVmFactory;
|
||||||
|
private readonly IDataModelUIService _dataModelUIService;
|
||||||
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
|
private DataModelDynamicViewModel _targetSelectionViewModel;
|
||||||
|
|
||||||
|
public DirectDataBindingModeViewModel(DirectDataBinding<TLayerProperty, TProperty> directDataBinding,
|
||||||
|
IProfileEditorService profileEditorService,
|
||||||
|
IDataModelUIService dataModelUIService,
|
||||||
|
IDataBindingsVmFactory dataBindingsVmFactory)
|
||||||
|
{
|
||||||
|
_profileEditorService = profileEditorService;
|
||||||
|
_dataModelUIService = dataModelUIService;
|
||||||
|
_dataBindingsVmFactory = dataBindingsVmFactory;
|
||||||
|
|
||||||
|
DirectDataBinding = directDataBinding;
|
||||||
|
ModifierViewModels = new BindableCollection<DataBindingModifierViewModel<TLayerProperty, TProperty>>();
|
||||||
|
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public DirectDataBinding<TLayerProperty, TProperty> DirectDataBinding { get; }
|
||||||
|
public BindableCollection<DataBindingModifierViewModel<TLayerProperty, TProperty>> ModifierViewModels { get; }
|
||||||
|
|
||||||
|
public DataModelDynamicViewModel TargetSelectionViewModel
|
||||||
|
{
|
||||||
|
get => _targetSelectionViewModel;
|
||||||
|
private set => SetAndNotify(ref _targetSelectionViewModel, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DirectDataBinding.SourceDataModel, DirectDataBinding.SourcePropertyPath);
|
||||||
|
TargetSelectionViewModel.FilterTypes = new[] {DirectDataBinding.DataBinding.GetTargetType()};
|
||||||
|
|
||||||
|
UpdateModifierViewModels();
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetTestValue()
|
||||||
|
{
|
||||||
|
return TargetSelectionViewModel.SelectedPropertyViewModel?.GetCurrentValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
|
{
|
||||||
|
DirectDataBinding.ModifiersUpdated += DirectDataBindingOnModifiersUpdated;
|
||||||
|
TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
||||||
|
TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected;
|
||||||
|
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Target
|
||||||
|
|
||||||
|
private void TargetSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
|
||||||
|
{
|
||||||
|
DirectDataBinding.UpdateSource(e.DataModelVisualizationViewModel.DataModel, e.DataModelVisualizationViewModel.PropertyPath);
|
||||||
|
Update();
|
||||||
|
|
||||||
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Modifiers
|
||||||
|
|
||||||
|
public void AddModifier()
|
||||||
|
{
|
||||||
|
DirectDataBinding.AddModifier(ProfileRightSideType.Dynamic);
|
||||||
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void UpdateModifierViewModels()
|
||||||
|
{
|
||||||
|
foreach (var dataBindingModifierViewModel in ModifierViewModels)
|
||||||
|
dataBindingModifierViewModel.Dispose();
|
||||||
|
ModifierViewModels.Clear();
|
||||||
|
|
||||||
|
foreach (var dataBindingModifier in DirectDataBinding.Modifiers)
|
||||||
|
ModifierViewModels.Add(_dataBindingsVmFactory.DataBindingModifierViewModel(dataBindingModifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DirectDataBindingOnModifiersUpdated(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
UpdateModifierViewModels();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
TargetSelectionViewModel.PropertySelected -= TargetSelectionViewModelOnPropertySelected;
|
||||||
|
TargetSelectionViewModel.Dispose();
|
||||||
|
DirectDataBinding.ModifiersUpdated -= DirectDataBindingOnModifiersUpdated;
|
||||||
|
|
||||||
|
foreach (var dataBindingModifierViewModel in ModifierViewModels)
|
||||||
|
dataBindingModifierViewModel.Dispose();
|
||||||
|
ModifierViewModels.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||||
|
{
|
||||||
|
public interface IDataBindingModeViewModel : IScreen, IDisposable
|
||||||
|
{
|
||||||
|
void Update();
|
||||||
|
object GetTestValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -78,7 +78,7 @@
|
|||||||
<!-- Left side -->
|
<!-- Left side -->
|
||||||
<Grid Grid.Column="0">
|
<Grid Grid.Column="0">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="56" />
|
<RowDefinition Height="48" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
@ -173,7 +173,7 @@
|
|||||||
</materialDesign:TransitionerSlide.BackwardWipe>
|
</materialDesign:TransitionerSlide.BackwardWipe>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="56" />
|
<RowDefinition Height="48" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
@ -208,7 +208,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- Timeline header body -->
|
<!-- Timeline header body -->
|
||||||
<controls:PropertyTimelineHeader Margin="0 25 0 0"
|
<controls:PropertyTimelineHeader Margin="0 18 0 0"
|
||||||
Fill="{DynamicResource MaterialDesignBody}"
|
Fill="{DynamicResource MaterialDesignBody}"
|
||||||
PixelsPerSecond="{Binding ProfileEditorService.PixelsPerSecond}"
|
PixelsPerSecond="{Binding ProfileEditorService.PixelsPerSecond}"
|
||||||
HorizontalOffset="{Binding ContentHorizontalOffset, ElementName=TimelineHeaderScrollViewer}"
|
HorizontalOffset="{Binding ContentHorizontalOffset, ElementName=TimelineHeaderScrollViewer}"
|
||||||
@ -250,7 +250,7 @@
|
|||||||
<materialDesign:TransitionerSlide.BackwardWipe>
|
<materialDesign:TransitionerSlide.BackwardWipe>
|
||||||
<materialDesign:CircleWipe />
|
<materialDesign:CircleWipe />
|
||||||
</materialDesign:TransitionerSlide.BackwardWipe>
|
</materialDesign:TransitionerSlide.BackwardWipe>
|
||||||
<Grid Background="{StaticResource MaterialDesignPaper}">
|
<Grid Background="{StaticResource MaterialDesignCardBackground}">
|
||||||
<ContentControl s:View.Model="{Binding DataBindingsViewModel}" />
|
<ContentControl s:View.Model="{Binding DataBindingsViewModel}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</materialDesign:TransitionerSlide>
|
</materialDesign:TransitionerSlide>
|
||||||
|
|||||||
@ -29,6 +29,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
set => SetAndNotify(ref _isVisible, value);
|
set => SetAndNotify(ref _isVisible, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsExpanded => false;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
TreePropertyViewModel?.Dispose();
|
TreePropertyViewModel?.Dispose();
|
||||||
|
|||||||
@ -129,9 +129,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline.Controls
|
|||||||
var typeFace = new Typeface(FontFamily, new FontStyle(), new FontWeight(), new FontStretch());
|
var typeFace = new Typeface(FontFamily, new FontStyle(), new FontWeight(), new FontStretch());
|
||||||
var formattedText = new FormattedText(text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeFace, 9, Fill, null, VisualTreeHelper.GetDpi(this).PixelsPerDip);
|
var formattedText = new FormattedText(text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeFace, 9, Fill, null, VisualTreeHelper.GetDpi(this).PixelsPerDip);
|
||||||
if (x == 0 && OffsetFirstValue)
|
if (x == 0 && OffsetFirstValue)
|
||||||
drawingContext.DrawText(formattedText, new Point(2, 2));
|
drawingContext.DrawText(formattedText, new Point(2, 5));
|
||||||
else
|
else
|
||||||
drawingContext.DrawText(formattedText, new Point(x - formattedText.Width / 2, 2));
|
drawingContext.DrawText(formattedText, new Point(x - formattedText.Width / 2, 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateTimeScale()
|
private void UpdateTimeScale()
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
@ -58,7 +59,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void ApplyKeyframesEnabled(bool enable)
|
private void ApplyKeyframesEnabled(bool enable)
|
||||||
{
|
{
|
||||||
// If enabling keyframes for the first time, add a keyframe with the current value at the current position
|
// If enabling keyframes for the first time, add a keyframe with the current value at the current position
|
||||||
@ -95,8 +96,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ITreePropertyViewModel : IScreen, IDisposable
|
public interface ITreePropertyViewModel : IScreen, INotifyPropertyChanged, IDisposable
|
||||||
{
|
{
|
||||||
bool HasPropertyInputViewModel { get; }
|
bool HasPropertyInputViewModel { get; }
|
||||||
|
bool DataBindingsOpen { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,6 +95,11 @@
|
|||||||
<Style TargetType="TreeViewItem" BasedOn="{StaticResource PropertyTreeStyle}">
|
<Style TargetType="TreeViewItem" BasedOn="{StaticResource PropertyTreeStyle}">
|
||||||
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
|
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
|
||||||
<Setter Property="Visibility" Value="{Binding IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
<Setter Property="Visibility" Value="{Binding IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding TreePropertyViewModel.DataBindingsOpen}" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</TreeView.ItemContainerStyle>
|
</TreeView.ItemContainerStyle>
|
||||||
<TreeView.Resources>
|
<TreeView.Resources>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user