mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Core - Added XML comments to all remaining public members/methods
Core - Refactored a lot of code for nullable reference types
This commit is contained in:
1 parent
61fc96742d
commit
a3cd32f6c4
107 files changed
+1150
-649
No files matched your search
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Artemis.Core.Properties;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
@@ -11,7 +8,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// A gradient containing a list of <see cref="ColorGradientStop" />s
|
||||
/// </summary>
|
||||
public class ColorGradient : INotifyPropertyChanged
|
||||
public class ColorGradient : CorePropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ColorGradient" /> class
|
||||
@@ -92,7 +89,8 @@ namespace Artemis.Core
|
||||
ColorGradientStop[] stops = Stops.OrderBy(x => x.Position).ToArray();
|
||||
if (position <= 0) return stops[0].Color;
|
||||
if (position >= 1) return stops[^1].Color;
|
||||
ColorGradientStop left = stops[0], right = null;
|
||||
ColorGradientStop left = stops[0];
|
||||
ColorGradientStop? right = null;
|
||||
foreach (ColorGradientStop stop in stops)
|
||||
{
|
||||
if (stop.Position >= position)
|
||||
@@ -130,18 +128,5 @@ namespace Artemis.Core
|
||||
|
||||
return gradient;
|
||||
}
|
||||
|
||||
#region PropertyChanged
|
||||
|
||||
/// <inheritdoc />
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
internal virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Artemis.Core.Properties;
|
||||
using SkiaSharp;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A color with a position, usually contained in a <see cref="ColorGradient" />
|
||||
/// </summary>
|
||||
public class ColorGradientStop : INotifyPropertyChanged
|
||||
public class ColorGradientStop : CorePropertyChanged
|
||||
{
|
||||
private SKColor _color;
|
||||
private float _position;
|
||||
@@ -28,12 +25,7 @@ namespace Artemis.Core
|
||||
public SKColor Color
|
||||
{
|
||||
get => _color;
|
||||
set
|
||||
{
|
||||
if (value.Equals(_color)) return;
|
||||
_color = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
set => SetAndNotify(ref _color, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,25 +34,7 @@ namespace Artemis.Core
|
||||
public float Position
|
||||
{
|
||||
get => _position;
|
||||
set
|
||||
{
|
||||
if (value.Equals(_position)) return;
|
||||
_position = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
set => SetAndNotify(ref _position, value);
|
||||
}
|
||||
|
||||
#region PropertyChanged
|
||||
|
||||
/// <inheritdoc />
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace Artemis.Core
|
||||
/// Gets the plugin this condition operator belongs to
|
||||
/// <para>Note: Not set until after registering</para>
|
||||
/// </summary>
|
||||
public Plugin Plugin { get; internal set; }
|
||||
public Plugin? Plugin { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the left side type of this condition operator
|
||||
@@ -64,9 +64,19 @@ namespace Artemis.Core
|
||||
internal abstract bool InternalEvaluate(object? leftSideValue, object? rightSideValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a side of a condition parameter
|
||||
/// </summary>
|
||||
public enum ConditionParameterSide
|
||||
{
|
||||
/// <summary>
|
||||
/// The left side of a condition parameter
|
||||
/// </summary>
|
||||
Left,
|
||||
|
||||
/// <summary>
|
||||
/// The right side of a condition parameter
|
||||
/// </summary>
|
||||
Right
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <returns></returns>
|
||||
internal abstract bool EvaluateObject(object target);
|
||||
internal abstract bool EvaluateObject(object? target);
|
||||
|
||||
internal abstract void Save();
|
||||
internal abstract DataModelConditionPartEntity GetEntity();
|
||||
@@ -104,14 +104,27 @@ namespace Artemis.Core
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler ChildAdded;
|
||||
public event EventHandler ChildRemoved;
|
||||
/// <summary>
|
||||
/// Occurs when a child-condition was added
|
||||
/// </summary>
|
||||
public event EventHandler? ChildAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a child-condition was removed
|
||||
/// </summary>
|
||||
public event EventHandler? ChildRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Invokers the <see cref="ChildAdded" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnChildAdded()
|
||||
{
|
||||
ChildAdded?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokers the <see cref="ChildRemoved" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnChildRemoved()
|
||||
{
|
||||
ChildRemoved?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
@@ -63,8 +63,8 @@ namespace Artemis.Core
|
||||
public override string ToString()
|
||||
{
|
||||
if (PredicateType == ProfileRightSideType.Dynamic)
|
||||
return $"[Dynamic] {LeftPath} {Operator.Description} {RightPath}";
|
||||
return $"[Static] {LeftPath} {Operator.Description} {RightStaticValue}";
|
||||
return $"[Dynamic] {LeftPath} {Operator?.Description} {RightPath}";
|
||||
return $"[Static] {LeftPath} {Operator?.Description} {RightStaticValue}";
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
@@ -138,7 +138,14 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the left path of this condition predicate
|
||||
/// </summary>
|
||||
protected abstract void InitializeLeftPath();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the right path of this condition predicate
|
||||
/// </summary>
|
||||
protected abstract void InitializeRightPath();
|
||||
|
||||
#endregion
|
||||
@@ -315,7 +322,7 @@ namespace Artemis.Core
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
internal override bool EvaluateObject(object target)
|
||||
internal override bool EvaluateObject(object? target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -344,7 +351,7 @@ namespace Artemis.Core
|
||||
|
||||
Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
|
||||
|
||||
if (Operator != null)
|
||||
if (Operator?.Plugin != null)
|
||||
{
|
||||
Entity.OperatorPluginGuid = Operator.Plugin.Guid;
|
||||
Entity.OperatorType = Operator.GetType().Name;
|
||||
@@ -358,7 +365,7 @@ namespace Artemis.Core
|
||||
private void ConditionOperatorStoreOnConditionOperatorAdded(object? sender, ConditionOperatorStoreEvent e)
|
||||
{
|
||||
BaseConditionOperator conditionOperator = e.Registration.ConditionOperator;
|
||||
if (Entity.OperatorPluginGuid == conditionOperator.Plugin.Guid && Entity.OperatorType == conditionOperator.GetType().Name)
|
||||
if (Entity.OperatorPluginGuid == conditionOperator.Plugin!.Guid && Entity.OperatorType == conditionOperator.GetType().Name)
|
||||
UpdateOperator(conditionOperator);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ namespace Artemis.Core
|
||||
public class DataModelConditionEvent : DataModelConditionPart
|
||||
{
|
||||
private bool _disposed;
|
||||
private bool _reinitializing;
|
||||
private IDataModelEvent? _event;
|
||||
private bool _eventTriggered;
|
||||
private bool _reinitializing;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="DataModelConditionEvent" /> class
|
||||
@@ -40,10 +40,13 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public DataModelPath? EventPath { get; private set; }
|
||||
|
||||
public Type? EventArgumentType { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the type of argument the event provides
|
||||
/// </summary>
|
||||
public Type? EventArgumentType { get; private set; }
|
||||
|
||||
internal DataModelConditionEventEntity Entity { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Evaluate()
|
||||
{
|
||||
@@ -62,22 +65,12 @@ namespace Artemis.Core
|
||||
|
||||
// If there is a child (root group), it must evaluate to true whenever the event triggered
|
||||
if (Children.Any())
|
||||
return Children[0].EvaluateObject(_event.LastEventArgumentsUntyped);
|
||||
return Children[0].EvaluateObject(_event?.LastEventArgumentsUntyped);
|
||||
|
||||
// If there are no children, we always evaluate to true whenever the event triggered
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SubscribeToDataModelEvent(IDataModelEvent dataModelEvent)
|
||||
{
|
||||
if (_event != null)
|
||||
_event.EventTriggered -= OnEventTriggered;
|
||||
|
||||
_event = dataModelEvent;
|
||||
if (_event != null)
|
||||
_event.EventTriggered += OnEventTriggered;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the event the condition is triggered by
|
||||
/// </summary>
|
||||
@@ -108,16 +101,6 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
private Type? GetEventArgumentType()
|
||||
{
|
||||
if (EventPath == null || !EventPath.IsValid)
|
||||
return null;
|
||||
|
||||
// Cannot rely on EventPath.GetValue() because part of the path might be null
|
||||
Type eventType = EventPath.GetPropertyType()!;
|
||||
return eventType.IsGenericType ? eventType.GetGenericArguments()[0] : typeof(DataModelEventArgs);
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -135,7 +118,7 @@ namespace Artemis.Core
|
||||
|
||||
#endregion
|
||||
|
||||
internal override bool EvaluateObject(object target)
|
||||
internal override bool EvaluateObject(object? target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -191,6 +174,26 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
private void SubscribeToDataModelEvent(IDataModelEvent dataModelEvent)
|
||||
{
|
||||
if (_event != null)
|
||||
_event.EventTriggered -= OnEventTriggered;
|
||||
|
||||
_event = dataModelEvent;
|
||||
if (_event != null)
|
||||
_event.EventTriggered += OnEventTriggered;
|
||||
}
|
||||
|
||||
private Type? GetEventArgumentType()
|
||||
{
|
||||
if (EventPath == null || !EventPath.IsValid)
|
||||
return null;
|
||||
|
||||
// Cannot rely on EventPath.GetValue() because part of the path might be null
|
||||
Type eventType = EventPath.GetPropertyType()!;
|
||||
return eventType.IsGenericType ? eventType.GetGenericArguments()[0] : typeof(DataModelEventArgs);
|
||||
}
|
||||
|
||||
private bool PointsToEvent(DataModelPath dataModelPath)
|
||||
{
|
||||
Type? type = dataModelPath.GetPropertyType();
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Artemis.Core
|
||||
throw new ArtemisCoreException("This data model condition event predicate does not belong to a data model condition event");
|
||||
}
|
||||
|
||||
private object? GetEventPathValue(DataModelPath path, object target)
|
||||
private object? GetEventPathValue(DataModelPath path, object? target)
|
||||
{
|
||||
lock (path)
|
||||
{
|
||||
@@ -67,6 +67,7 @@ namespace Artemis.Core
|
||||
|
||||
#region Initialization
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void InitializeLeftPath()
|
||||
{
|
||||
if (Entity.LeftPath != null)
|
||||
@@ -75,6 +76,7 @@ namespace Artemis.Core
|
||||
: null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void InitializeRightPath()
|
||||
{
|
||||
if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null)
|
||||
@@ -122,7 +124,7 @@ namespace Artemis.Core
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool EvaluateObject(object target)
|
||||
internal override bool EvaluateObject(object? target)
|
||||
{
|
||||
if (Operator == null || LeftPath == null || !LeftPath.IsValid)
|
||||
return false;
|
||||
|
||||
@@ -46,12 +46,14 @@ namespace Artemis.Core
|
||||
|
||||
#region Initialization
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void InitializeLeftPath()
|
||||
{
|
||||
if (Entity.LeftPath != null)
|
||||
LeftPath = new DataModelPath(null, Entity.LeftPath);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void InitializeRightPath()
|
||||
{
|
||||
if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null)
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Artemis.Core
|
||||
/// Creates a new instance of the <see cref="DataModelConditionGroup" /> class
|
||||
/// </summary>
|
||||
/// <param name="parent"></param>
|
||||
public DataModelConditionGroup(DataModelConditionPart parent)
|
||||
public DataModelConditionGroup(DataModelConditionPart? parent)
|
||||
{
|
||||
Parent = parent;
|
||||
Entity = new DataModelConditionGroupEntity();
|
||||
@@ -32,7 +32,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
/// <param name="parent"></param>
|
||||
/// <param name="entity"></param>
|
||||
public DataModelConditionGroup(DataModelConditionPart parent, DataModelConditionGroupEntity entity)
|
||||
public DataModelConditionGroup(DataModelConditionPart? parent, DataModelConditionGroupEntity entity)
|
||||
{
|
||||
Parent = parent;
|
||||
Entity = entity;
|
||||
@@ -124,7 +124,7 @@ namespace Artemis.Core
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
internal override bool EvaluateObject(object target)
|
||||
internal override bool EvaluateObject(object? target)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("DataModelConditionGroup");
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace Artemis.Core
|
||||
{
|
||||
Type listType = ListPath.GetPropertyType()!;
|
||||
ListType = listType.GetGenericEnumerableType();
|
||||
IsPrimitiveList = ListType.IsPrimitive || ListType.IsEnum || ListType == typeof(string);
|
||||
IsPrimitiveList = ListType == null || ListType.IsPrimitive || ListType.IsEnum || ListType == typeof(string);
|
||||
|
||||
// Create a new root group
|
||||
AddChild(new DataModelConditionGroup(this));
|
||||
@@ -188,7 +188,7 @@ namespace Artemis.Core
|
||||
if (ListPath.IsValid)
|
||||
{
|
||||
ListType = listType.GetGenericEnumerableType();
|
||||
IsPrimitiveList = ListType.IsPrimitive || ListType.IsEnum || ListType == typeof(string);
|
||||
IsPrimitiveList = ListType == null || ListType.IsPrimitive || ListType.IsEnum || ListType == typeof(string);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Artemis.Core
|
||||
throw new ArtemisCoreException("This data model condition list predicate does not belong to a data model condition list");
|
||||
}
|
||||
|
||||
private object? GetListPathValue(DataModelPath path, object target)
|
||||
private object? GetListPathValue(DataModelPath path, object? target)
|
||||
{
|
||||
if (!(path.Target is ListPredicateWrapperDataModel wrapper))
|
||||
throw new ArtemisCoreException("Data model condition list predicate has a path with an invalid target");
|
||||
@@ -64,6 +64,7 @@ namespace Artemis.Core
|
||||
|
||||
#region Initialization
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void InitializeLeftPath()
|
||||
{
|
||||
if (Entity.LeftPath != null)
|
||||
@@ -72,6 +73,7 @@ namespace Artemis.Core
|
||||
: null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void InitializeRightPath()
|
||||
{
|
||||
if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null)
|
||||
@@ -121,7 +123,7 @@ namespace Artemis.Core
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool EvaluateObject(object target)
|
||||
internal override bool EvaluateObject(object? target)
|
||||
{
|
||||
if (Operator == null || LeftPath == null || !LeftPath.IsValid)
|
||||
return false;
|
||||
|
||||
+5
-2
@@ -19,11 +19,14 @@ namespace Artemis.Core
|
||||
Feature = Constants.CorePluginFeature;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last arguments of this event as an object
|
||||
/// </summary>
|
||||
[DataModelIgnore]
|
||||
public object? UntypedArguments { get; set; }
|
||||
public object? UntypedArguments { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="EventPredicateWrapperDataModel"/> class
|
||||
/// Creates a new instance of the <see cref="EventPredicateWrapperDataModel" /> class
|
||||
/// </summary>
|
||||
public static EventPredicateWrapperDataModel Create(Type type)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace Artemis.Core
|
||||
Feature = Constants.CorePluginFeature;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value of this list as an object
|
||||
/// </summary>
|
||||
[DataModelIgnore]
|
||||
public object? UntypedValue { get; set; }
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
public class DataBinding<TLayerProperty, TProperty> : IDataBinding
|
||||
{
|
||||
private TProperty _currentValue;
|
||||
private TProperty _currentValue = default!;
|
||||
private TProperty _previousValue = default!;
|
||||
private bool _disposed;
|
||||
private TimeSpan _easingProgress;
|
||||
private TProperty _previousValue;
|
||||
|
||||
internal DataBinding(DataBindingRegistration<TLayerProperty, TProperty> dataBindingRegistration)
|
||||
{
|
||||
@@ -34,7 +34,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets the data binding registration this data binding is based upon
|
||||
/// </summary>
|
||||
public DataBindingRegistration<TLayerProperty, TProperty> Registration { get; private set; }
|
||||
public DataBindingRegistration<TLayerProperty, TProperty>? Registration { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layer property this data binding targets
|
||||
@@ -44,12 +44,12 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets the converter used to apply this data binding to the <see cref="LayerProperty" />
|
||||
/// </summary>
|
||||
public DataBindingConverter<TLayerProperty, TProperty> Converter { get; private set; }
|
||||
public DataBindingConverter<TLayerProperty, TProperty>? Converter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data binding mode
|
||||
/// </summary>
|
||||
public IDataBindingMode<TLayerProperty, TProperty> DataBindingMode { get; private set; }
|
||||
public IDataBindingMode<TLayerProperty, TProperty>? DataBindingMode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the easing time of the data binding
|
||||
@@ -93,9 +93,9 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Returns the type of the target property of this data binding
|
||||
/// </summary>
|
||||
public Type GetTargetType()
|
||||
public Type? GetTargetType()
|
||||
{
|
||||
return Registration.PropertyExpression.ReturnType;
|
||||
return Registration?.PropertyExpression.ReturnType;
|
||||
}
|
||||
|
||||
private void ResetEasing(TProperty value)
|
||||
@@ -111,15 +111,15 @@ namespace Artemis.Core
|
||||
throw new ArgumentNullException(nameof(dataBindingRegistration));
|
||||
|
||||
dataBindingRegistration.DataBinding = this;
|
||||
Converter = dataBindingRegistration?.Converter;
|
||||
Converter = dataBindingRegistration.Converter;
|
||||
Registration = dataBindingRegistration;
|
||||
|
||||
if (GetTargetType().IsValueType)
|
||||
if (GetTargetType()!.IsValueType)
|
||||
{
|
||||
if (_currentValue == null)
|
||||
_currentValue = default;
|
||||
_currentValue = default!;
|
||||
if (_previousValue == null)
|
||||
_previousValue = default;
|
||||
_previousValue = default!;
|
||||
}
|
||||
|
||||
Converter?.Initialize(this);
|
||||
@@ -127,7 +127,7 @@ namespace Artemis.Core
|
||||
|
||||
private TProperty GetInterpolatedValue()
|
||||
{
|
||||
if (_easingProgress == EasingTime || !Converter.SupportsInterpolate)
|
||||
if (_easingProgress == EasingTime || Converter == null || !Converter.SupportsInterpolate)
|
||||
return _currentValue;
|
||||
|
||||
double easingAmount = _easingProgress.TotalSeconds / EasingTime.TotalSeconds;
|
||||
@@ -180,7 +180,8 @@ namespace Artemis.Core
|
||||
{
|
||||
_disposed = true;
|
||||
|
||||
Registration.DataBinding = null;
|
||||
if (Registration != null)
|
||||
Registration.DataBinding = null;
|
||||
DataBindingMode?.Dispose();
|
||||
}
|
||||
|
||||
@@ -234,7 +235,7 @@ namespace Artemis.Core
|
||||
throw new ObjectDisposedException("DataBinding");
|
||||
|
||||
// General
|
||||
DataBindingRegistration<TLayerProperty, TProperty> registration = LayerProperty.GetDataBindingRegistration<TProperty>(Entity.TargetExpression);
|
||||
DataBindingRegistration<TLayerProperty, TProperty>? registration = LayerProperty.GetDataBindingRegistration<TProperty>(Entity.TargetExpression);
|
||||
if (registration != null)
|
||||
ApplyRegistration(registration);
|
||||
|
||||
@@ -253,8 +254,10 @@ namespace Artemis.Core
|
||||
if (!LayerProperty.Entity.DataBindingEntities.Contains(Entity))
|
||||
LayerProperty.Entity.DataBindingEntities.Add(Entity);
|
||||
|
||||
// General
|
||||
Entity.TargetExpression = Registration.PropertyExpression.ToString();
|
||||
// Don't save an invalid state
|
||||
if (Registration != null)
|
||||
Entity.TargetExpression = Registration.PropertyExpression.ToString();
|
||||
|
||||
Entity.EasingTime = EasingTime;
|
||||
Entity.EasingFunction = (int) EasingFunction;
|
||||
|
||||
|
||||
@@ -13,22 +13,22 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets a dynamically compiled getter pointing to the data bound property
|
||||
/// </summary>
|
||||
public Func<TLayerProperty, TProperty> GetExpression { get; private set; }
|
||||
public Func<TLayerProperty, TProperty>? GetExpression { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dynamically compiled setter pointing to the data bound property used for value types
|
||||
/// </summary>
|
||||
public Action<TProperty> ValueTypeSetExpression { get; private set; }
|
||||
public Action<TProperty>? ValueTypeSetExpression { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dynamically compiled setter pointing to the data bound property used for reference types
|
||||
/// </summary>
|
||||
public Action<TLayerProperty, TProperty> ReferenceTypeSetExpression { get; private set; }
|
||||
public Action<TLayerProperty, TProperty>? ReferenceTypeSetExpression { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data binding this converter is applied to
|
||||
/// </summary>
|
||||
public DataBinding<TLayerProperty, TProperty> DataBinding { get; private set; }
|
||||
public DataBinding<TLayerProperty, TProperty>? DataBinding { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not this data binding converter supports the <see cref="Sum" /> method
|
||||
@@ -65,6 +65,8 @@ namespace Artemis.Core
|
||||
/// <param name="value"></param>
|
||||
public virtual void ApplyValue(TProperty value)
|
||||
{
|
||||
if (DataBinding == null)
|
||||
throw new ArtemisCoreException("Data binding converter is not yet initialized");
|
||||
if (ReferenceTypeSetExpression != null)
|
||||
ReferenceTypeSetExpression(DataBinding.LayerProperty.CurrentValue, value);
|
||||
else if (ValueTypeSetExpression != null)
|
||||
@@ -76,6 +78,8 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public virtual TProperty GetValue()
|
||||
{
|
||||
if (DataBinding == null || GetExpression == null)
|
||||
throw new ArtemisCoreException("Data binding converter is not yet initialized");
|
||||
return GetExpression(DataBinding.LayerProperty.CurrentValue);
|
||||
}
|
||||
|
||||
@@ -84,7 +88,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public virtual TProperty ConvertFromObject(object? source)
|
||||
{
|
||||
return (TProperty) Convert.ChangeType(source, typeof(TProperty));
|
||||
return (TProperty) Convert.ChangeType(source, typeof(TProperty))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -96,6 +100,9 @@ namespace Artemis.Core
|
||||
|
||||
internal void Initialize(DataBinding<TLayerProperty, TProperty> dataBinding)
|
||||
{
|
||||
if (dataBinding.Registration == null)
|
||||
throw new ArtemisCoreException("Cannot initialize a data binding converter for a data binding without a registration");
|
||||
|
||||
DataBinding = dataBinding;
|
||||
GetExpression = dataBinding.Registration.PropertyExpression.Compile();
|
||||
CreateSetExpression();
|
||||
@@ -106,14 +113,14 @@ namespace Artemis.Core
|
||||
private void CreateSetExpression()
|
||||
{
|
||||
// If the registration does not point towards a member of LayerProperty<T>.CurrentValue, assign directly to LayerProperty<T>.CurrentValue
|
||||
if (DataBinding.Registration.Member == null)
|
||||
if (DataBinding!.Registration?.Member == null)
|
||||
{
|
||||
CreateSetCurrentValueExpression();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the member of LayerProperty<T>.CurrentValue has a setter
|
||||
MethodInfo setterMethod = null;
|
||||
MethodInfo? setterMethod = null;
|
||||
if (DataBinding.Registration.Member is PropertyInfo propertyInfo)
|
||||
setterMethod = propertyInfo.GetSetMethod();
|
||||
// If there is no setter, the built-in data binding cannot do its job, stay null
|
||||
@@ -130,6 +137,9 @@ namespace Artemis.Core
|
||||
|
||||
private void CreateSetReferenceTypeExpression()
|
||||
{
|
||||
if (DataBinding!.Registration?.Member == null)
|
||||
throw new ArtemisCoreException("Cannot create value setter for data binding without a registration");
|
||||
|
||||
ParameterExpression propertyValue = Expression.Parameter(typeof(TProperty), "propertyValue");
|
||||
ParameterExpression parameter = Expression.Parameter(typeof(TLayerProperty), "currentValue");
|
||||
MemberExpression memberAccess = Expression.MakeMemberAccess(parameter, DataBinding.Registration.Member);
|
||||
@@ -141,6 +151,9 @@ namespace Artemis.Core
|
||||
|
||||
private void CreateSetValueTypeExpression()
|
||||
{
|
||||
if (DataBinding!.Registration?.Member == null)
|
||||
throw new ArtemisCoreException("Cannot create value setter for data binding without a registration");
|
||||
|
||||
ParameterExpression propertyValue = Expression.Parameter(typeof(TProperty), "propertyValue");
|
||||
ParameterExpression variableCurrent = Expression.Variable(typeof(TLayerProperty), "current");
|
||||
ConstantExpression layerProperty = Expression.Constant(DataBinding.LayerProperty);
|
||||
@@ -161,7 +174,7 @@ namespace Artemis.Core
|
||||
private void CreateSetCurrentValueExpression()
|
||||
{
|
||||
ParameterExpression propertyValue = Expression.Parameter(typeof(TProperty), "propertyValue");
|
||||
ConstantExpression layerProperty = Expression.Constant(DataBinding.LayerProperty);
|
||||
ConstantExpression layerProperty = Expression.Constant(DataBinding!.LayerProperty);
|
||||
MemberExpression layerPropertyMemberAccess = Expression.MakeMemberAccess(layerProperty,
|
||||
DataBinding.LayerProperty.GetType().GetMember(nameof(DataBinding.LayerProperty.CurrentValue))[0]);
|
||||
|
||||
|
||||
@@ -38,28 +38,28 @@ namespace Artemis.Core
|
||||
|
||||
/// <summary>
|
||||
/// Gets the member the <see cref="PropertyExpression" /> targets
|
||||
/// <para><c>null</c> if the <see cref="PropertyExpression" /> is not a member expression</para>
|
||||
/// <para><see langword="null"/> if the <see cref="PropertyExpression" /> is not a member expression</para>
|
||||
/// </summary>
|
||||
public MemberInfo Member { get; }
|
||||
public MemberInfo? Member { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data binding created using this registration
|
||||
/// </summary>
|
||||
public DataBinding<TLayerProperty, TProperty> DataBinding { get; internal set; }
|
||||
public DataBinding<TLayerProperty, TProperty>? DataBinding { get; internal set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IDataBinding GetDataBinding()
|
||||
public IDataBinding? GetDataBinding()
|
||||
{
|
||||
return DataBinding;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IDataBinding CreateDataBinding()
|
||||
public IDataBinding? CreateDataBinding()
|
||||
{
|
||||
if (DataBinding != null)
|
||||
return DataBinding;
|
||||
|
||||
DataBindingEntity dataBinding = LayerProperty.Entity.DataBindingEntities.FirstOrDefault(e => e.TargetExpression == PropertyExpression.ToString());
|
||||
DataBindingEntity? dataBinding = LayerProperty.Entity.DataBindingEntities.FirstOrDefault(e => e.TargetExpression == PropertyExpression.ToString());
|
||||
if (dataBinding == null)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
/// <summary>
|
||||
/// Returns the data binding applied using this registration
|
||||
/// </summary>
|
||||
public IDataBinding GetDataBinding();
|
||||
public IDataBinding? GetDataBinding();
|
||||
|
||||
/// <summary>
|
||||
/// If found, creates a data binding from storage
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IDataBinding CreateDataBinding();
|
||||
IDataBinding? CreateDataBinding();
|
||||
}
|
||||
}
|
||||
+9
-8
@@ -21,13 +21,13 @@ namespace Artemis.Core
|
||||
Load();
|
||||
}
|
||||
|
||||
internal ConditionalDataBindingEntity Entity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of conditions applied to this data binding
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<DataBindingCondition<TLayerProperty, TProperty>> Conditions => _conditions.AsReadOnly();
|
||||
|
||||
internal ConditionalDataBindingEntity Entity { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public DataBinding<TLayerProperty, TProperty> DataBinding { get; }
|
||||
|
||||
@@ -37,9 +37,7 @@ namespace Artemis.Core
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("ConditionalDataBinding");
|
||||
|
||||
DataBindingCondition<TLayerProperty, TProperty> condition = Conditions.FirstOrDefault(c => c.Evaluate());
|
||||
if (condition != null)
|
||||
Console.WriteLine();
|
||||
DataBindingCondition<TLayerProperty, TProperty>? condition = Conditions.FirstOrDefault(c => c.Evaluate());
|
||||
return condition == null ? baseValue : condition.Value;
|
||||
}
|
||||
|
||||
@@ -75,7 +73,7 @@ namespace Artemis.Core
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Removes a condition from the conditional data binding's <see cref="Conditions" /> collection and disposes it
|
||||
/// </summary>
|
||||
@@ -111,7 +109,7 @@ namespace Artemis.Core
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Storage
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -138,8 +136,11 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Occurs when a condition is added or removed
|
||||
/// </summary>
|
||||
public event EventHandler ConditionsUpdated;
|
||||
public event EventHandler? ConditionsUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="ConditionsUpdated" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnConditionsUpdated()
|
||||
{
|
||||
ConditionsUpdated?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
+6
-1
@@ -18,6 +18,8 @@ namespace Artemis.Core
|
||||
ConditionalDataBinding = conditionalDataBinding ?? throw new ArgumentNullException(nameof(conditionalDataBinding));
|
||||
Order = conditionalDataBinding.Conditions.Count + 1;
|
||||
Condition = new DataModelConditionGroup(null);
|
||||
Value = default!;
|
||||
|
||||
Entity = new DataBindingConditionEntity();
|
||||
Save();
|
||||
}
|
||||
@@ -26,6 +28,9 @@ namespace Artemis.Core
|
||||
{
|
||||
ConditionalDataBinding = conditionalDataBinding ?? throw new ArgumentNullException(nameof(conditionalDataBinding));
|
||||
Entity = entity;
|
||||
Condition = null!;
|
||||
Value = default!;
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
@@ -83,7 +88,7 @@ namespace Artemis.Core
|
||||
? new DataModelConditionGroup(null, Entity.Condition)
|
||||
: new DataModelConditionGroup(null);
|
||||
|
||||
Value = Entity.Value == null ? default : JsonConvert.DeserializeObject<TProperty>(Entity.Value);
|
||||
Value = (Entity.Value == null ? default : JsonConvert.DeserializeObject<TProperty>(Entity.Value))!;
|
||||
Order = Entity.Order;
|
||||
}
|
||||
|
||||
|
||||
+17
-5
@@ -15,7 +15,7 @@ namespace Artemis.Core
|
||||
/// Gets the plugin this data binding modifier belongs to
|
||||
/// <para>Note: Not set until after registering</para>
|
||||
/// </summary>
|
||||
public Plugin Plugin { get; internal set; }
|
||||
public Plugin? Plugin { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value type of this modifier type
|
||||
@@ -35,17 +35,17 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets or sets the icon of this modifier
|
||||
/// </summary>
|
||||
public abstract string Icon { get; }
|
||||
public abstract string? Icon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description of this modifier
|
||||
/// </summary>
|
||||
public virtual string Description => null;
|
||||
public virtual string? Description => null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the category of this modifier
|
||||
/// </summary>
|
||||
public virtual string Category => null;
|
||||
public virtual string? Category => null;
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the given type is supported by the modifier
|
||||
@@ -69,14 +69,26 @@ namespace Artemis.Core
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="currentValue">The current value before modification, type should match <see cref="ValueType" /></param>
|
||||
/// <param name="parameterValue">The parameter to use for the modification, type should match <see cref="ParameterType" /></param>
|
||||
/// <param name="parameterValue">
|
||||
/// The parameter to use for the modification, type should match <see cref="ParameterType" />
|
||||
/// </param>
|
||||
/// <returns>The modified value, with a type of <see cref="ValueType" /></returns>
|
||||
internal abstract object? InternalApply(object? currentValue, object? parameterValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a part of a modifier type
|
||||
/// </summary>
|
||||
public enum ModifierTypePart
|
||||
{
|
||||
/// <summary>
|
||||
/// The value part of a modifier, backed by <see cref="DataBindingModifierType{TValue}.ValueType" />
|
||||
/// </summary>
|
||||
Value,
|
||||
|
||||
/// <summary>
|
||||
/// The parameter part of a modifier, backed by <see cref="DataBindingModifierType{TValue,TParameter}.ParameterType" />
|
||||
/// </summary>
|
||||
Parameter
|
||||
}
|
||||
}
|
||||
@@ -103,8 +103,8 @@ namespace Artemis.Core
|
||||
return;
|
||||
}
|
||||
|
||||
Type targetType = DirectDataBinding.DataBinding.GetTargetType();
|
||||
if (!modifierType.SupportsType(targetType, ModifierTypePart.Value))
|
||||
Type? targetType = DirectDataBinding.DataBinding.GetTargetType();
|
||||
if (targetType != null && !modifierType.SupportsType(targetType, ModifierTypePart.Value))
|
||||
throw new ArtemisCoreException($"Cannot apply modifier type {modifierType.GetType().Name} to this modifier because " +
|
||||
$"it does not support this data binding's type {targetType.Name}");
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace Artemis.Core
|
||||
/// Updates the parameter of the modifier, makes the modifier static and re-compiles the expression
|
||||
/// </summary>
|
||||
/// <param name="staticValue">The static value to use as a parameter</param>
|
||||
public void UpdateParameterStatic(object staticValue)
|
||||
public void UpdateParameterStatic(object? staticValue)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("DataBindingModifier");
|
||||
@@ -167,10 +167,10 @@ namespace Artemis.Core
|
||||
ParameterPath?.Dispose();
|
||||
ParameterPath = null;
|
||||
|
||||
Type parameterType = ModifierType?.ParameterType ?? DirectDataBinding.DataBinding.GetTargetType();
|
||||
Type? parameterType = ModifierType?.ParameterType ?? DirectDataBinding.DataBinding.GetTargetType();
|
||||
|
||||
// If not null ensure the types match and if not, convert it
|
||||
if (staticValue != null && staticValue.GetType() == parameterType)
|
||||
if (parameterType == null || staticValue != null && staticValue.GetType() == parameterType)
|
||||
ParameterStaticValue = staticValue;
|
||||
else if (staticValue != null)
|
||||
ParameterStaticValue = Convert.ChangeType(staticValue, parameterType);
|
||||
@@ -189,7 +189,7 @@ namespace Artemis.Core
|
||||
// Modifier type
|
||||
if (Entity.ModifierTypePluginGuid != null && ModifierType == null)
|
||||
{
|
||||
BaseDataBindingModifierType modifierType = DataBindingModifierTypeStore.Get(Entity.ModifierTypePluginGuid.Value, Entity.ModifierType)?.DataBindingModifierType;
|
||||
BaseDataBindingModifierType? modifierType = DataBindingModifierTypeStore.Get(Entity.ModifierTypePluginGuid.Value, Entity.ModifierType)?.DataBindingModifierType;
|
||||
if (modifierType != null)
|
||||
UpdateModifierType(modifierType);
|
||||
}
|
||||
@@ -203,18 +203,21 @@ namespace Artemis.Core
|
||||
else if (ParameterType == ProfileRightSideType.Static && Entity.ParameterStaticValue != null)
|
||||
{
|
||||
// Use the target type so JSON.NET has a better idea what to do
|
||||
Type parameterType = ModifierType?.ParameterType ?? DirectDataBinding.DataBinding.GetTargetType();
|
||||
object staticValue;
|
||||
Type? parameterType = ModifierType?.ParameterType ?? DirectDataBinding.DataBinding.GetTargetType();
|
||||
object? staticValue = null;
|
||||
|
||||
try
|
||||
{
|
||||
staticValue = JsonConvert.DeserializeObject(Entity.ParameterStaticValue, parameterType);
|
||||
staticValue = parameterType != null
|
||||
? JsonConvert.DeserializeObject(Entity.ParameterStaticValue, parameterType)
|
||||
: JsonConvert.DeserializeObject(Entity.ParameterStaticValue);
|
||||
}
|
||||
// If deserialization fails, use the type's default
|
||||
catch (JsonSerializationException e)
|
||||
{
|
||||
DeserializationLogger.LogModifierDeserializationFailure(GetType().Name, e);
|
||||
staticValue = Activator.CreateInstance(parameterType);
|
||||
if (parameterType != null)
|
||||
staticValue = Activator.CreateInstance(parameterType);
|
||||
}
|
||||
|
||||
UpdateParameterStatic(staticValue);
|
||||
@@ -235,7 +238,7 @@ namespace Artemis.Core
|
||||
DirectDataBinding.Entity.Modifiers.Add(Entity);
|
||||
|
||||
// Modifier
|
||||
if (ModifierType != null)
|
||||
if (ModifierType?.Plugin != null)
|
||||
{
|
||||
Entity.ModifierType = ModifierType.GetType().Name;
|
||||
Entity.ModifierTypePluginGuid = ModifierType.Plugin.Guid;
|
||||
@@ -280,17 +283,17 @@ namespace Artemis.Core
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void DataBindingModifierTypeStoreOnDataBindingModifierAdded(object sender, DataBindingModifierTypeStoreEvent e)
|
||||
private void DataBindingModifierTypeStoreOnDataBindingModifierAdded(object? sender, DataBindingModifierTypeStoreEvent e)
|
||||
{
|
||||
if (ModifierType != null)
|
||||
return;
|
||||
|
||||
BaseDataBindingModifierType modifierType = e.TypeRegistration.DataBindingModifierType;
|
||||
if (modifierType.Plugin.Guid == Entity.ModifierTypePluginGuid && modifierType.GetType().Name == Entity.ModifierType)
|
||||
if (modifierType.Plugin!.Guid == Entity.ModifierTypePluginGuid && modifierType.GetType().Name == Entity.ModifierType)
|
||||
UpdateModifierType(modifierType);
|
||||
}
|
||||
|
||||
private void DataBindingModifierTypeStoreOnDataBindingModifierRemoved(object sender, DataBindingModifierTypeStoreEvent e)
|
||||
private void DataBindingModifierTypeStoreOnDataBindingModifierRemoved(object? sender, DataBindingModifierTypeStoreEvent e)
|
||||
{
|
||||
if (e.TypeRegistration.DataBindingModifierType == ModifierType)
|
||||
UpdateModifierType(null);
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Artemis.Core
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("DirectDataBinding");
|
||||
|
||||
if (SourcePath == null || !SourcePath.IsValid)
|
||||
if (SourcePath == null || !SourcePath.IsValid || DataBinding.Converter == null)
|
||||
return baseValue;
|
||||
|
||||
object? dataBindingValue = SourcePath.GetValue();
|
||||
@@ -188,6 +188,9 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public event EventHandler? ModifiersUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="ModifiersUpdated" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnModifiersUpdated()
|
||||
{
|
||||
ModifiersUpdated?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
@@ -318,18 +318,24 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Occurs whenever the path becomes invalid
|
||||
/// </summary>
|
||||
public event EventHandler PathInvalidated;
|
||||
public event EventHandler? PathInvalidated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs whenever the path becomes valid
|
||||
/// </summary>
|
||||
public event EventHandler PathValidated;
|
||||
public event EventHandler? PathValidated;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="PathInvalidated" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnPathValidated()
|
||||
{
|
||||
PathValidated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="PathValidated" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnPathInvalidated()
|
||||
{
|
||||
PathInvalidated?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
@@ -115,8 +115,8 @@ namespace Artemis.Core
|
||||
// Dynamic types have a data model description
|
||||
if (Type == DataModelPathSegmentType.Dynamic)
|
||||
return (GetValue() as DataModel)?.DataModelDescription;
|
||||
if (IsStartSegment && DataModelPath.Target is DataModel targetDataModel)
|
||||
return targetDataModel.DataModelDescription;
|
||||
if (IsStartSegment && DataModelPath.Target != null)
|
||||
return DataModelPath.Target.DataModelDescription;
|
||||
if (IsStartSegment)
|
||||
return null;
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace Artemis.Core
|
||||
return null;
|
||||
|
||||
// Static types may have one as an attribute
|
||||
DataModelPropertyAttribute? attribute = (DataModelPropertyAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(DataModelPropertyAttribute));
|
||||
DataModelPropertyAttribute? attribute = (DataModelPropertyAttribute?) Attribute.GetCustomAttribute(propertyInfo, typeof(DataModelPropertyAttribute));
|
||||
if (attribute != null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(attribute.Name))
|
||||
@@ -187,8 +187,8 @@ namespace Artemis.Core
|
||||
return CreateExpression(parameter, expression, nullCondition);
|
||||
|
||||
// If a dynamic data model is found the use that
|
||||
bool hasDynamicDataModel = _dynamicDataModel.DynamicDataModels.TryGetValue(Identifier, out DataModel dynamicDataModel);
|
||||
if (hasDynamicDataModel)
|
||||
bool hasDynamicDataModel = _dynamicDataModel.DynamicDataModels.TryGetValue(Identifier, out DataModel? dynamicDataModel);
|
||||
if (hasDynamicDataModel && dynamicDataModel != null)
|
||||
DetermineDynamicType(dynamicDataModel);
|
||||
|
||||
_dynamicDataModel.DynamicDataModelAdded += DynamicDataModelOnDynamicDataModelAdded;
|
||||
@@ -219,7 +219,7 @@ namespace Artemis.Core
|
||||
accessorExpression = Expression.Call(
|
||||
expression,
|
||||
nameof(DataModel.DynamicChild),
|
||||
new[] {DynamicDataModelType},
|
||||
DynamicDataModelType != null ? new[] {DynamicDataModelType} : null,
|
||||
Expression.Constant(Identifier)
|
||||
);
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace Artemis.Core
|
||||
Name = name;
|
||||
Enabled = true;
|
||||
|
||||
_layerEffects = new List<BaseLayerEffect>();
|
||||
_expandedPropertyGroups = new List<string>();
|
||||
LayerEffectsList = new List<BaseLayerEffect>();
|
||||
ExpandedPropertyGroups = new List<string>();
|
||||
|
||||
Parent.AddChild(this);
|
||||
}
|
||||
@@ -47,8 +47,8 @@ namespace Artemis.Core
|
||||
Enabled = folderEntity.Enabled;
|
||||
Order = folderEntity.Order;
|
||||
|
||||
_layerEffects = new List<BaseLayerEffect>();
|
||||
_expandedPropertyGroups = new List<string>();
|
||||
LayerEffectsList = new List<BaseLayerEffect>();
|
||||
ExpandedPropertyGroups = new List<string>();
|
||||
|
||||
Load();
|
||||
}
|
||||
@@ -58,11 +58,6 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public bool IsRootFolder => Parent == Profile;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the longest timeline of all this folders children
|
||||
/// </summary>
|
||||
public Timeline LongestChildTimeline { get; private set; }
|
||||
|
||||
internal FolderEntity FolderEntity { get; set; }
|
||||
|
||||
internal override RenderElementEntity RenderElementEntity => FolderEntity;
|
||||
@@ -78,6 +73,7 @@ namespace Artemis.Core
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
if (Disposed)
|
||||
@@ -129,6 +125,9 @@ namespace Artemis.Core
|
||||
/// <returns>The newly created copy</returns>
|
||||
public Folder CreateCopy()
|
||||
{
|
||||
if (Parent == null)
|
||||
throw new ArtemisCoreException("Cannot create a copy of a folder without a parent");
|
||||
|
||||
JsonSerializerSettings settings = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All};
|
||||
FolderEntity entityCopy = JsonConvert.DeserializeObject<FolderEntity>(JsonConvert.SerializeObject(FolderEntity, settings), settings)!;
|
||||
entityCopy.Id = Guid.NewGuid();
|
||||
@@ -139,12 +138,13 @@ namespace Artemis.Core
|
||||
return new Folder(Profile, Parent, entityCopy);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[Folder] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
|
||||
}
|
||||
|
||||
public void CalculateRenderProperties()
|
||||
internal void CalculateRenderProperties()
|
||||
{
|
||||
if (Disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
@@ -163,57 +163,9 @@ namespace Artemis.Core
|
||||
OnRenderPropertiesUpdated();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
Disposed = true;
|
||||
|
||||
foreach (ProfileElement profileElement in Children)
|
||||
profileElement.Dispose();
|
||||
Renderer.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
internal override void Load()
|
||||
{
|
||||
_expandedPropertyGroups.AddRange(FolderEntity.ExpandedPropertyGroups);
|
||||
|
||||
// Load child folders
|
||||
foreach (FolderEntity childFolder in Profile.ProfileEntity.Folders.Where(f => f.ParentId == EntityId))
|
||||
ChildrenList.Add(new Folder(Profile, this, childFolder));
|
||||
// Load child layers
|
||||
foreach (LayerEntity childLayer in Profile.ProfileEntity.Layers.Where(f => f.ParentId == EntityId))
|
||||
ChildrenList.Add(new Layer(Profile, this, childLayer));
|
||||
|
||||
// Ensure order integrity, should be unnecessary but no one is perfect specially me
|
||||
ChildrenList = ChildrenList.OrderBy(c => c.Order).ToList();
|
||||
for (int index = 0; index < ChildrenList.Count; index++)
|
||||
ChildrenList[index].Order = index + 1;
|
||||
|
||||
LoadRenderElement();
|
||||
}
|
||||
|
||||
internal override void Save()
|
||||
{
|
||||
if (Disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
FolderEntity.Id = EntityId;
|
||||
FolderEntity.ParentId = Parent?.EntityId ?? new Guid();
|
||||
|
||||
FolderEntity.Order = Order;
|
||||
FolderEntity.Name = Name;
|
||||
FolderEntity.Enabled = Enabled;
|
||||
|
||||
FolderEntity.ProfileId = Profile.EntityId;
|
||||
FolderEntity.ExpandedPropertyGroups.Clear();
|
||||
FolderEntity.ExpandedPropertyGroups.AddRange(_expandedPropertyGroups);
|
||||
|
||||
SaveRenderElement();
|
||||
}
|
||||
|
||||
#region Rendering
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Render(SKCanvas canvas)
|
||||
{
|
||||
if (Disposed)
|
||||
@@ -278,9 +230,62 @@ namespace Artemis.Core
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
Disposed = true;
|
||||
|
||||
foreach (ProfileElement profileElement in Children)
|
||||
profileElement.Dispose();
|
||||
Renderer.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
internal override void Load()
|
||||
{
|
||||
ExpandedPropertyGroups.AddRange(FolderEntity.ExpandedPropertyGroups);
|
||||
|
||||
// Load child folders
|
||||
foreach (FolderEntity childFolder in Profile.ProfileEntity.Folders.Where(f => f.ParentId == EntityId))
|
||||
ChildrenList.Add(new Folder(Profile, this, childFolder));
|
||||
// Load child layers
|
||||
foreach (LayerEntity childLayer in Profile.ProfileEntity.Layers.Where(f => f.ParentId == EntityId))
|
||||
ChildrenList.Add(new Layer(Profile, this, childLayer));
|
||||
|
||||
// Ensure order integrity, should be unnecessary but no one is perfect specially me
|
||||
ChildrenList = ChildrenList.OrderBy(c => c.Order).ToList();
|
||||
for (int index = 0; index < ChildrenList.Count; index++)
|
||||
ChildrenList[index].Order = index + 1;
|
||||
|
||||
LoadRenderElement();
|
||||
}
|
||||
|
||||
internal override void Save()
|
||||
{
|
||||
if (Disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
FolderEntity.Id = EntityId;
|
||||
FolderEntity.ParentId = Parent?.EntityId ?? new Guid();
|
||||
|
||||
FolderEntity.Order = Order;
|
||||
FolderEntity.Name = Name;
|
||||
FolderEntity.Enabled = Enabled;
|
||||
|
||||
FolderEntity.ProfileId = Profile.EntityId;
|
||||
FolderEntity.ExpandedPropertyGroups.Clear();
|
||||
FolderEntity.ExpandedPropertyGroups.AddRange(ExpandedPropertyGroups);
|
||||
|
||||
SaveRenderElement();
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler RenderPropertiesUpdated;
|
||||
/// <summary>
|
||||
/// Occurs when a property affecting the rendering properties of this folder has been updated
|
||||
/// </summary>
|
||||
public event EventHandler? RenderPropertiesUpdated;
|
||||
|
||||
private void OnRenderPropertiesUpdated()
|
||||
{
|
||||
|
||||
@@ -17,10 +17,10 @@ namespace Artemis.Core
|
||||
public sealed class Layer : RenderProfileElement
|
||||
{
|
||||
private LayerGeneralProperties _general;
|
||||
private BaseLayerBrush _layerBrush;
|
||||
private LayerShape _layerShape;
|
||||
private List<ArtemisLed> _leds;
|
||||
private BaseLayerBrush? _layerBrush;
|
||||
private LayerTransformProperties _transform;
|
||||
private LayerShape? _layerShape;
|
||||
private List<ArtemisLed> _leds;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="Layer" /> class and adds itself to the child collection of the provided
|
||||
@@ -37,12 +37,12 @@ namespace Artemis.Core
|
||||
Profile = Parent.Profile;
|
||||
Name = name;
|
||||
Enabled = true;
|
||||
General = new LayerGeneralProperties();
|
||||
Transform = new LayerTransformProperties();
|
||||
_general = new LayerGeneralProperties();
|
||||
_transform = new LayerTransformProperties();
|
||||
|
||||
_layerEffects = new List<BaseLayerEffect>();
|
||||
LayerEffectsList = new List<BaseLayerEffect>();
|
||||
_leds = new List<ArtemisLed>();
|
||||
_expandedPropertyGroups = new List<string>();
|
||||
ExpandedPropertyGroups = new List<string>();
|
||||
|
||||
Initialize();
|
||||
Parent.AddChild(this);
|
||||
@@ -55,12 +55,12 @@ namespace Artemis.Core
|
||||
|
||||
Profile = profile;
|
||||
Parent = parent;
|
||||
General = new LayerGeneralProperties();
|
||||
Transform = new LayerTransformProperties();
|
||||
|
||||
_layerEffects = new List<BaseLayerEffect>();
|
||||
_general = new LayerGeneralProperties();
|
||||
_transform = new LayerTransformProperties();
|
||||
|
||||
LayerEffectsList = new List<BaseLayerEffect>();
|
||||
_leds = new List<ArtemisLed>();
|
||||
_expandedPropertyGroups = new List<string>();
|
||||
ExpandedPropertyGroups = new List<string>();
|
||||
|
||||
Load();
|
||||
Initialize();
|
||||
@@ -74,7 +74,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Defines the shape that is rendered by the <see cref="LayerBrush" />.
|
||||
/// </summary>
|
||||
public LayerShape LayerShape
|
||||
public LayerShape? LayerShape
|
||||
{
|
||||
get => _layerShape;
|
||||
set
|
||||
@@ -85,24 +85,30 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the general properties of the layer
|
||||
/// </summary>
|
||||
[PropertyGroupDescription(Name = "General", Description = "A collection of general properties")]
|
||||
public LayerGeneralProperties General
|
||||
{
|
||||
get => _general;
|
||||
set => SetAndNotify(ref _general, value);
|
||||
private set => SetAndNotify(ref _general, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the transform properties of the layer
|
||||
/// </summary>
|
||||
[PropertyGroupDescription(Name = "Transform", Description = "A collection of transformation properties")]
|
||||
public LayerTransformProperties Transform
|
||||
{
|
||||
get => _transform;
|
||||
set => SetAndNotify(ref _transform, value);
|
||||
private set => SetAndNotify(ref _transform, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The brush that will fill the <see cref="LayerShape" />.
|
||||
/// </summary>
|
||||
public BaseLayerBrush LayerBrush
|
||||
public BaseLayerBrush? LayerBrush
|
||||
{
|
||||
get => _layerBrush;
|
||||
internal set => SetAndNotify(ref _layerBrush, value);
|
||||
@@ -111,20 +117,24 @@ namespace Artemis.Core
|
||||
internal LayerEntity LayerEntity { get; set; }
|
||||
|
||||
internal override RenderElementEntity RenderElementEntity => LayerEntity;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep copy of the layer
|
||||
/// </summary>
|
||||
/// <returns>The newly created copy</returns>
|
||||
public Layer CreateCopy()
|
||||
{
|
||||
if (Parent == null)
|
||||
throw new ArtemisCoreException("Cannot create a copy of a layer without a parent");
|
||||
|
||||
JsonSerializerSettings settings = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All};
|
||||
LayerEntity entityCopy = JsonConvert.DeserializeObject<LayerEntity>(JsonConvert.SerializeObject(LayerEntity, settings), settings)!;
|
||||
entityCopy.Id = Guid.NewGuid();
|
||||
entityCopy.Name += " - Copy";
|
||||
|
||||
Layer copy = new Layer(Profile, Parent, entityCopy);
|
||||
copy.ChangeLayerBrush(LayerBrush.Descriptor);
|
||||
if (LayerBrush?.Descriptor != null)
|
||||
copy.ChangeLayerBrush(LayerBrush.Descriptor);
|
||||
copy.AddLeds(Leds);
|
||||
|
||||
Parent.AddChild(copy, Order + 1);
|
||||
@@ -162,8 +172,8 @@ namespace Artemis.Core
|
||||
|
||||
// Brush first in case it depends on any of the other disposables during it's own disposal
|
||||
_layerBrush?.Dispose();
|
||||
_general?.Dispose();
|
||||
_transform?.Dispose();
|
||||
_general.Dispose();
|
||||
_transform.Dispose();
|
||||
Renderer.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
@@ -177,14 +187,14 @@ namespace Artemis.Core
|
||||
LayerBrushStore.LayerBrushRemoved += LayerBrushStoreOnLayerBrushRemoved;
|
||||
|
||||
// Layers have two hardcoded property groups, instantiate them
|
||||
Attribute? generalAttribute = Attribute.GetCustomAttribute(
|
||||
GetType().GetProperty(nameof(General)),
|
||||
Attribute generalAttribute = Attribute.GetCustomAttribute(
|
||||
GetType().GetProperty(nameof(General))!,
|
||||
typeof(PropertyGroupDescriptionAttribute)
|
||||
);
|
||||
Attribute? transformAttribute = Attribute.GetCustomAttribute(
|
||||
GetType().GetProperty(nameof(Transform)),
|
||||
)!;
|
||||
Attribute transformAttribute = Attribute.GetCustomAttribute(
|
||||
GetType().GetProperty(nameof(Transform))!,
|
||||
typeof(PropertyGroupDescriptionAttribute)
|
||||
);
|
||||
)!;
|
||||
General.GroupDescription = (PropertyGroupDescriptionAttribute) generalAttribute;
|
||||
General.Initialize(this, "General.", Constants.CorePluginFeature);
|
||||
Transform.GroupDescription = (PropertyGroupDescriptionAttribute) transformAttribute;
|
||||
@@ -204,7 +214,7 @@ namespace Artemis.Core
|
||||
Enabled = LayerEntity.Enabled;
|
||||
Order = LayerEntity.Order;
|
||||
|
||||
_expandedPropertyGroups.AddRange(LayerEntity.ExpandedPropertyGroups);
|
||||
ExpandedPropertyGroups.AddRange(LayerEntity.ExpandedPropertyGroups);
|
||||
LoadRenderElement();
|
||||
}
|
||||
|
||||
@@ -221,11 +231,11 @@ namespace Artemis.Core
|
||||
LayerEntity.Name = Name;
|
||||
LayerEntity.ProfileId = Profile.EntityId;
|
||||
LayerEntity.ExpandedPropertyGroups.Clear();
|
||||
LayerEntity.ExpandedPropertyGroups.AddRange(_expandedPropertyGroups);
|
||||
LayerEntity.ExpandedPropertyGroups.AddRange(ExpandedPropertyGroups);
|
||||
|
||||
General.ApplyToEntity();
|
||||
Transform.ApplyToEntity();
|
||||
LayerBrush?.BaseProperties.ApplyToEntity();
|
||||
LayerBrush?.BaseProperties?.ApplyToEntity();
|
||||
|
||||
// LEDs
|
||||
LayerEntity.Leds.Clear();
|
||||
@@ -246,7 +256,7 @@ namespace Artemis.Core
|
||||
|
||||
#region Shape management
|
||||
|
||||
private void ShapeTypeOnCurrentValueSet(object sender, EventArgs e)
|
||||
private void ShapeTypeOnCurrentValueSet(object? sender, EventArgs e)
|
||||
{
|
||||
ApplyShapeType();
|
||||
}
|
||||
@@ -316,8 +326,11 @@ namespace Artemis.Core
|
||||
{
|
||||
General.Update(timeline);
|
||||
Transform.Update(timeline);
|
||||
LayerBrush.BaseProperties?.Update(timeline);
|
||||
LayerBrush.Update(timeline.Delta.TotalSeconds);
|
||||
if (LayerBrush != null)
|
||||
{
|
||||
LayerBrush.BaseProperties?.Update(timeline);
|
||||
LayerBrush.Update(timeline.Delta.TotalSeconds);
|
||||
}
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||
{
|
||||
@@ -328,6 +341,9 @@ namespace Artemis.Core
|
||||
|
||||
private void RenderTimeline(Timeline timeline, SKCanvas canvas)
|
||||
{
|
||||
if (Path == null || LayerBrush == null)
|
||||
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
||||
|
||||
if (timeline.IsFinished)
|
||||
return;
|
||||
|
||||
@@ -392,6 +408,11 @@ namespace Artemis.Core
|
||||
|
||||
private void DelegateRendering(SKRect bounds)
|
||||
{
|
||||
if (LayerBrush == null)
|
||||
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
||||
if (Renderer.Canvas == null || Renderer.Paint == null)
|
||||
throw new ArtemisCoreException("Failed to open layer render context");
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||
baseLayerEffect.PreProcess(Renderer.Canvas, bounds, Renderer.Paint);
|
||||
|
||||
@@ -459,12 +480,18 @@ namespace Artemis.Core
|
||||
/// If true, treats the layer as if it is located at 0,0 instead of its actual position on the
|
||||
/// surface
|
||||
/// </param>
|
||||
/// <param name="includeTranslation">Whether translation should be included</param>
|
||||
/// <param name="includeScale">Whether the scale should be included</param>
|
||||
/// <param name="includeRotation">Whether the rotation should be included</param>
|
||||
/// <returns>The transformation matrix containing the current transformation settings</returns>
|
||||
public SKMatrix GetTransformMatrix(bool zeroBased, bool includeTranslation, bool includeScale, bool includeRotation)
|
||||
{
|
||||
if (Disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
if (Path == null)
|
||||
return SKMatrix.Empty;
|
||||
|
||||
SKSize sizeProperty = Transform.Scale.CurrentValue;
|
||||
float rotationProperty = Transform.Rotation.CurrentValue;
|
||||
|
||||
@@ -478,25 +505,23 @@ namespace Artemis.Core
|
||||
SKMatrix transform = SKMatrix.Empty;
|
||||
|
||||
if (includeTranslation)
|
||||
{
|
||||
// transform is always SKMatrix.Empty here...
|
||||
transform = SKMatrix.MakeTranslation(x, y);
|
||||
}
|
||||
transform = SKMatrix.CreateTranslation(x, y);
|
||||
|
||||
if (includeScale)
|
||||
{
|
||||
if (transform == SKMatrix.Empty)
|
||||
transform = SKMatrix.MakeScale(sizeProperty.Width / 100f, sizeProperty.Height / 100f, anchorPosition.X, anchorPosition.Y);
|
||||
transform = SKMatrix.CreateScale(sizeProperty.Width / 100f, sizeProperty.Height / 100f, anchorPosition.X, anchorPosition.Y);
|
||||
else
|
||||
transform = transform.PostConcat(SKMatrix.MakeScale(sizeProperty.Width / 100f, sizeProperty.Height / 100f, anchorPosition.X, anchorPosition.Y));
|
||||
transform = transform.PostConcat(SKMatrix.CreateScale(sizeProperty.Width / 100f, sizeProperty.Height / 100f, anchorPosition.X, anchorPosition.Y));
|
||||
}
|
||||
|
||||
if (includeRotation)
|
||||
{
|
||||
if (transform == SKMatrix.Empty)
|
||||
transform = SKMatrix.MakeRotationDegrees(rotationProperty, anchorPosition.X, anchorPosition.Y);
|
||||
transform = SKMatrix.CreateRotationDegrees(rotationProperty, anchorPosition.X, anchorPosition.Y);
|
||||
else
|
||||
transform = transform.PostConcat(SKMatrix.MakeRotationDegrees(rotationProperty, anchorPosition.X, anchorPosition.Y));
|
||||
transform = transform.PostConcat(SKMatrix.CreateRotationDegrees(rotationProperty, anchorPosition.X, anchorPosition.Y));
|
||||
}
|
||||
|
||||
return transform;
|
||||
@@ -568,8 +593,8 @@ namespace Artemis.Core
|
||||
List<ArtemisLed> availableLeds = surface.Devices.SelectMany(d => d.Leds).ToList();
|
||||
foreach (LedEntity ledEntity in LayerEntity.Leds)
|
||||
{
|
||||
ArtemisLed match = availableLeds.FirstOrDefault(a => a.Device.RgbDevice.GetDeviceIdentifier() == ledEntity.DeviceIdentifier &&
|
||||
a.RgbLed.Id.ToString() == ledEntity.LedName);
|
||||
ArtemisLed? match = availableLeds.FirstOrDefault(a => a.Device.RgbDevice.GetDeviceIdentifier() == ledEntity.DeviceIdentifier &&
|
||||
a.RgbLed.Id.ToString() == ledEntity.LedName);
|
||||
if (match != null)
|
||||
leds.Add(match);
|
||||
}
|
||||
@@ -598,7 +623,7 @@ namespace Artemis.Core
|
||||
}
|
||||
|
||||
// Ensure the brush reference matches the brush
|
||||
LayerBrushReference current = General.BrushReference.BaseValue;
|
||||
LayerBrushReference? current = General.BrushReference.BaseValue;
|
||||
if (!descriptor.MatchesLayerBrushReference(current))
|
||||
General.BrushReference.BaseValue = new LayerBrushReference(descriptor);
|
||||
|
||||
@@ -620,11 +645,13 @@ namespace Artemis.Core
|
||||
|
||||
internal void ActivateLayerBrush()
|
||||
{
|
||||
LayerBrushReference current = General.BrushReference.CurrentValue;
|
||||
LayerBrushReference? current = General.BrushReference.CurrentValue;
|
||||
if (current == null)
|
||||
return;
|
||||
|
||||
LayerBrushDescriptor? descriptor = LayerBrushStore.Get(current.LayerBrushProviderId, current.BrushType)?.LayerBrushDescriptor;
|
||||
LayerBrushDescriptor? descriptor = current.LayerBrushProviderId != null && current.BrushType != null
|
||||
? LayerBrushStore.Get(current.LayerBrushProviderId, current.BrushType)?.LayerBrushDescriptor
|
||||
: null;
|
||||
descriptor?.CreateInstance(this);
|
||||
|
||||
OnLayerBrushUpdated();
|
||||
@@ -646,19 +673,19 @@ namespace Artemis.Core
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void LayerBrushStoreOnLayerBrushRemoved(object sender, LayerBrushStoreEvent e)
|
||||
private void LayerBrushStoreOnLayerBrushRemoved(object? sender, LayerBrushStoreEvent e)
|
||||
{
|
||||
if (LayerBrush?.Descriptor == e.Registration.LayerBrushDescriptor)
|
||||
DeactivateLayerBrush();
|
||||
}
|
||||
|
||||
private void LayerBrushStoreOnLayerBrushAdded(object sender, LayerBrushStoreEvent e)
|
||||
private void LayerBrushStoreOnLayerBrushAdded(object? sender, LayerBrushStoreEvent e)
|
||||
{
|
||||
if (LayerBrush != null || General.BrushReference?.CurrentValue == null)
|
||||
if (LayerBrush != null || !General.PropertiesInitialized)
|
||||
return;
|
||||
|
||||
LayerBrushReference current = General.BrushReference.CurrentValue;
|
||||
if (e.Registration.PluginFeature.Id == current.LayerBrushProviderId &&
|
||||
LayerBrushReference? current = General.BrushReference.CurrentValue;
|
||||
if (e.Registration.PluginFeature.Id == current?.LayerBrushProviderId &&
|
||||
e.Registration.LayerBrushDescriptor.LayerBrushType.Name == current.BrushType)
|
||||
ActivateLayerBrush();
|
||||
}
|
||||
@@ -667,8 +694,15 @@ namespace Artemis.Core
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler RenderPropertiesUpdated;
|
||||
public event EventHandler LayerBrushUpdated;
|
||||
/// <summary>
|
||||
/// Occurs when a property affecting the rendering properties of this layer has been updated
|
||||
/// </summary>
|
||||
public event EventHandler? RenderPropertiesUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the layer brush of this layer has been updated
|
||||
/// </summary>
|
||||
public event EventHandler? LayerBrushUpdated;
|
||||
|
||||
private void OnRenderPropertiesUpdated()
|
||||
{
|
||||
@@ -683,15 +717,35 @@ namespace Artemis.Core
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a type of layer shape
|
||||
/// </summary>
|
||||
public enum LayerShapeType
|
||||
{
|
||||
/// <summary>
|
||||
/// A circular layer shape
|
||||
/// </summary>
|
||||
Ellipse,
|
||||
|
||||
/// <summary>
|
||||
/// A rectangular layer shape
|
||||
/// </summary>
|
||||
Rectangle
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a layer transform mode
|
||||
/// </summary>
|
||||
public enum LayerTransformMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Normal transformation
|
||||
/// </summary>
|
||||
Normal,
|
||||
|
||||
/// <summary>
|
||||
/// Transforms only a clip
|
||||
/// </summary>
|
||||
Clip
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,17 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public class LayerBrushReference
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="LayerBrushReference" /> class
|
||||
/// </summary>
|
||||
public LayerBrushReference()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="LayerBrushReference" /> class
|
||||
/// </summary>
|
||||
/// <param name="descriptor">The descriptor to point the new reference at</param>
|
||||
public LayerBrushReference(LayerBrushDescriptor descriptor)
|
||||
{
|
||||
LayerBrushProviderId = descriptor.Provider.Id;
|
||||
@@ -20,11 +27,11 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// The ID of the layer brush provided the brush was provided by
|
||||
/// </summary>
|
||||
public string LayerBrushProviderId { get; set; }
|
||||
public string? LayerBrushProviderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The full type name of the brush descriptor
|
||||
/// </summary>
|
||||
public string BrushType { get; set; }
|
||||
public string? BrushType { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,51 @@
|
||||
using SkiaSharp;
|
||||
|
||||
#pragma warning disable 8618
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the general properties of a layer
|
||||
/// </summary>
|
||||
public class LayerGeneralProperties : LayerPropertyGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of shape to draw in this layer
|
||||
/// </summary>
|
||||
[PropertyDescription(Name = "Shape type", Description = "The type of shape to draw in this layer")]
|
||||
public EnumLayerProperty<LayerShapeType> ShapeType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How to blend this layer into the resulting image
|
||||
/// </summary>
|
||||
[PropertyDescription(Name = "Blend mode", Description = "How to blend this layer into the resulting image")]
|
||||
public EnumLayerProperty<SKBlendMode> BlendMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How the transformation properties are applied to the layer
|
||||
/// </summary>
|
||||
[PropertyDescription(Name = "Transform mode", Description = "How the transformation properties are applied to the layer")]
|
||||
public EnumLayerProperty<LayerTransformMode> TransformMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of brush to use for this layer
|
||||
/// </summary>
|
||||
[PropertyDescription(Name = "Brush type", Description = "The type of brush to use for this layer")]
|
||||
public LayerBrushReferenceLayerProperty BrushReference { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void PopulateDefaults()
|
||||
{
|
||||
ShapeType.DefaultValue = LayerShapeType.Rectangle;
|
||||
BlendMode.DefaultValue = SKBlendMode.SrcOver;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void EnableProperties()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DisableProperties()
|
||||
{
|
||||
}
|
||||
|
||||
+9
-6
@@ -2,27 +2,30 @@
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a description attribute used to decorate layer properties
|
||||
/// </summary>
|
||||
public class PropertyDescriptionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The user-friendly name for this property, shown in the UI
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user-friendly description for this property, shown in the UI
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Input prefix to show before input elements in the UI
|
||||
/// </summary>
|
||||
public string InputPrefix { get; set; }
|
||||
public string? InputPrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Input affix to show behind input elements in the UI
|
||||
/// </summary>
|
||||
public string InputAffix { get; set; }
|
||||
public string? InputAffix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The input drag step size, used in the UI
|
||||
@@ -32,12 +35,12 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Minimum input value, only enforced in the UI
|
||||
/// </summary>
|
||||
public object MinInputValue { get; set; }
|
||||
public object? MinInputValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum input value, only enforced in the UI
|
||||
/// </summary>
|
||||
public object MaxInputValue { get; set; }
|
||||
public object? MaxInputValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not keyframes are always disabled
|
||||
|
||||
+5
-2
@@ -2,16 +2,19 @@
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a description attribute used to decorate layer property groups
|
||||
/// </summary>
|
||||
public class PropertyGroupDescriptionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The user-friendly name for this property, shown in the UI.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user-friendly description for this property, shown in the UI.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,22 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
protected LayerProperty()
|
||||
{
|
||||
// Cant define generic types as nullable ¯\_(ツ)_/¯
|
||||
CurrentValue = default!;
|
||||
DefaultValue = default!;
|
||||
|
||||
_baseValue = default!;
|
||||
_keyframes = new List<LayerPropertyKeyframe<T>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the type of the property
|
||||
/// </summary>
|
||||
public Type GetPropertyType()
|
||||
{
|
||||
return typeof(T);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public PropertyDescriptionAttribute PropertyDescription { get; internal set; }
|
||||
|
||||
@@ -57,14 +70,6 @@ namespace Artemis.Core
|
||||
dataBinding.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the type of the property
|
||||
/// </summary>
|
||||
public Type GetPropertyType()
|
||||
{
|
||||
return typeof(T);
|
||||
}
|
||||
|
||||
#region Hierarchy
|
||||
|
||||
private bool _isHidden;
|
||||
@@ -150,11 +155,13 @@ namespace Artemis.Core
|
||||
throw new ObjectDisposedException("LayerProperty");
|
||||
|
||||
if (time == null || !KeyframesEnabled || !KeyframesSupported)
|
||||
{
|
||||
BaseValue = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If on a keyframe, update the keyframe
|
||||
LayerPropertyKeyframe<T> currentKeyframe = Keyframes.FirstOrDefault(k => k.Position == time.Value);
|
||||
LayerPropertyKeyframe<T>? currentKeyframe = Keyframes.FirstOrDefault(k => k.Position == time.Value);
|
||||
// Create a new keyframe if none found
|
||||
if (currentKeyframe == null)
|
||||
AddKeyframe(new LayerPropertyKeyframe<T>(value, time.Value, Easings.Functions.Linear, this));
|
||||
@@ -222,12 +229,12 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets the current keyframe in the timeline according to the current progress
|
||||
/// </summary>
|
||||
public LayerPropertyKeyframe<T> CurrentKeyframe { get; protected set; }
|
||||
public LayerPropertyKeyframe<T>? CurrentKeyframe { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next keyframe in the timeline according to the current progress
|
||||
/// </summary>
|
||||
public LayerPropertyKeyframe<T> NextKeyframe { get; protected set; }
|
||||
public LayerPropertyKeyframe<T>? NextKeyframe { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a keyframe to the layer property
|
||||
@@ -249,26 +256,6 @@ namespace Artemis.Core
|
||||
OnKeyframeAdded();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a keyframe from the layer property
|
||||
/// </summary>
|
||||
/// <param name="keyframe">The keyframe to remove</param>
|
||||
public LayerPropertyKeyframe<T> CopyKeyframe(LayerPropertyKeyframe<T> keyframe)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("LayerProperty");
|
||||
|
||||
LayerPropertyKeyframe<T> newKeyframe = new LayerPropertyKeyframe<T>(
|
||||
keyframe.Value,
|
||||
keyframe.Position,
|
||||
keyframe.EasingFunction,
|
||||
keyframe.LayerProperty
|
||||
);
|
||||
AddKeyframe(newKeyframe);
|
||||
|
||||
return newKeyframe;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a keyframe from the layer property
|
||||
/// </summary>
|
||||
@@ -282,7 +269,6 @@ namespace Artemis.Core
|
||||
return;
|
||||
|
||||
_keyframes.Remove(keyframe);
|
||||
keyframe.LayerProperty = null;
|
||||
SortKeyframes();
|
||||
OnKeyframeRemoved();
|
||||
}
|
||||
@@ -303,14 +289,25 @@ namespace Artemis.Core
|
||||
// The current keyframe is the last keyframe before the current time
|
||||
CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= timeline.Position);
|
||||
// Keyframes are sorted by position so we can safely assume the next keyframe's position is after the current
|
||||
int nextIndex = _keyframes.IndexOf(CurrentKeyframe) + 1;
|
||||
NextKeyframe = _keyframes.Count > nextIndex ? _keyframes[nextIndex] : null;
|
||||
if (CurrentKeyframe != null)
|
||||
{
|
||||
int nextIndex = _keyframes.IndexOf(CurrentKeyframe) + 1;
|
||||
NextKeyframe = _keyframes.Count > nextIndex ? _keyframes[nextIndex] : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
NextKeyframe = null;
|
||||
}
|
||||
|
||||
// No need to update the current value if either of the keyframes are null
|
||||
if (CurrentKeyframe == null)
|
||||
{
|
||||
CurrentValue = _keyframes.Any() ? _keyframes[0].Value : BaseValue;
|
||||
}
|
||||
else if (NextKeyframe == null)
|
||||
{
|
||||
CurrentValue = CurrentKeyframe.Value;
|
||||
}
|
||||
// Only determine progress and current value if both keyframes are present
|
||||
else
|
||||
{
|
||||
@@ -325,8 +322,11 @@ namespace Artemis.Core
|
||||
|
||||
#region Data bindings
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
internal readonly List<IDataBindingRegistration> _dataBindingRegistrations = new List<IDataBindingRegistration>();
|
||||
|
||||
internal readonly List<IDataBinding> _dataBindings = new List<IDataBinding>();
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether data bindings are supported on this type of property
|
||||
@@ -342,27 +342,36 @@ namespace Artemis.Core
|
||||
/// Gets a data binding registration by the expression used to register it
|
||||
/// <para>Note: The expression must exactly match the one used to register the data binding</para>
|
||||
/// </summary>
|
||||
public DataBindingRegistration<T, TProperty> GetDataBindingRegistration<TProperty>(Expression<Func<T, TProperty>> propertyExpression)
|
||||
public DataBindingRegistration<T, TProperty>? GetDataBindingRegistration<TProperty>(Expression<Func<T, TProperty>> propertyExpression)
|
||||
{
|
||||
return GetDataBindingRegistration<TProperty>(propertyExpression.ToString());
|
||||
}
|
||||
|
||||
public DataBindingRegistration<T, TProperty> GetDataBindingRegistration<TProperty>(string expression)
|
||||
internal DataBindingRegistration<T, TProperty>? GetDataBindingRegistration<TProperty>(string expression)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("LayerProperty");
|
||||
|
||||
IDataBindingRegistration match = _dataBindingRegistrations.FirstOrDefault(r => r is DataBindingRegistration<T, TProperty> registration &&
|
||||
registration.PropertyExpression.ToString() == expression);
|
||||
|
||||
return (DataBindingRegistration<T, TProperty>) match;
|
||||
IDataBindingRegistration? match = _dataBindingRegistrations.FirstOrDefault(r => r is DataBindingRegistration<T, TProperty> registration &&
|
||||
registration.PropertyExpression.ToString() == expression);
|
||||
return (DataBindingRegistration<T, TProperty>?) match;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list containing all data binding registrations of this layer property
|
||||
/// </summary>
|
||||
/// <returns>A list containing all data binding registrations of this layer property</returns>
|
||||
public List<IDataBindingRegistration> GetAllDataBindingRegistrations()
|
||||
{
|
||||
return _dataBindingRegistrations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a data binding property so that is available to the data binding system
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty">The type of the layer property</typeparam>
|
||||
/// <param name="propertyExpression">The expression pointing to the value to register</param>
|
||||
/// <param name="converter">The converter to use while applying the data binding</param>
|
||||
public void RegisterDataBindingProperty<TProperty>(Expression<Func<T, TProperty>> propertyExpression, DataBindingConverter<T, TProperty> converter)
|
||||
{
|
||||
if (_disposed)
|
||||
@@ -372,10 +381,8 @@ namespace Artemis.Core
|
||||
throw new ArtemisCoreException("Provided expression is invalid, it must be 'value => value' or 'value => value.Property'");
|
||||
|
||||
if (converter.SupportedType != propertyExpression.ReturnType)
|
||||
{
|
||||
throw new ArtemisCoreException($"Cannot register data binding property for property {PropertyDescription.Name} " +
|
||||
"because the provided converter does not support the property's type");
|
||||
}
|
||||
|
||||
_dataBindingRegistrations.Add(new DataBindingRegistration<T, TProperty>(this, converter, propertyExpression));
|
||||
}
|
||||
@@ -412,7 +419,8 @@ namespace Artemis.Core
|
||||
|
||||
_dataBindings.Remove(dataBinding);
|
||||
|
||||
dataBinding.Registration.DataBinding = null;
|
||||
if (dataBinding.Registration != null)
|
||||
dataBinding.Registration.DataBinding = null;
|
||||
dataBinding.Dispose();
|
||||
OnDataBindingDisabled(new LayerPropertyEventArgs<T>(dataBinding.LayerProperty));
|
||||
}
|
||||
@@ -471,17 +479,15 @@ namespace Artemis.Core
|
||||
if (!IsLoadedFromStorage)
|
||||
ApplyDefaultValue();
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Entity.Value != null)
|
||||
BaseValue = JsonConvert.DeserializeObject<T>(Entity.Value);
|
||||
}
|
||||
catch (JsonException e)
|
||||
catch (JsonException)
|
||||
{
|
||||
// ignored for now
|
||||
}
|
||||
}
|
||||
|
||||
CurrentValue = BaseValue;
|
||||
KeyframesEnabled = Entity.KeyframesEnabled;
|
||||
@@ -494,7 +500,7 @@ namespace Artemis.Core
|
||||
.Select(k => new LayerPropertyKeyframe<T>(JsonConvert.DeserializeObject<T>(k.Value), k.Position, (Easings.Functions) k.EasingFunction, this))
|
||||
);
|
||||
}
|
||||
catch (JsonException e)
|
||||
catch (JsonException)
|
||||
{
|
||||
// ignored for now
|
||||
}
|
||||
@@ -502,15 +508,14 @@ namespace Artemis.Core
|
||||
_dataBindings.Clear();
|
||||
foreach (IDataBindingRegistration dataBindingRegistration in _dataBindingRegistrations)
|
||||
{
|
||||
IDataBinding dataBinding = dataBindingRegistration.CreateDataBinding();
|
||||
IDataBinding? dataBinding = dataBindingRegistration.CreateDataBinding();
|
||||
if (dataBinding != null)
|
||||
_dataBindings.Add(dataBinding);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the property to the underlying property entity that was configured when calling
|
||||
/// <see cref="ApplyToLayerProperty" />
|
||||
/// Saves the property to the underlying property entity
|
||||
/// </summary>
|
||||
public void Save()
|
||||
{
|
||||
@@ -542,79 +547,103 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Occurs once every frame when the layer property is updated
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs<T>> Updated;
|
||||
public event EventHandler<LayerPropertyEventArgs<T>>? Updated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the current value of the layer property was updated by some form of input
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs<T>> CurrentValueSet;
|
||||
public event EventHandler<LayerPropertyEventArgs<T>>? CurrentValueSet;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the <see cref="IsHidden" /> value of the layer property was updated
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs<T>> VisibilityChanged;
|
||||
public event EventHandler<LayerPropertyEventArgs<T>>? VisibilityChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when keyframes are enabled/disabled
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs<T>> KeyframesToggled;
|
||||
public event EventHandler<LayerPropertyEventArgs<T>>? KeyframesToggled;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a new keyframe was added to the layer property
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs<T>> KeyframeAdded;
|
||||
public event EventHandler<LayerPropertyEventArgs<T>>? KeyframeAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a keyframe was removed from the layer property
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs<T>> KeyframeRemoved;
|
||||
public event EventHandler<LayerPropertyEventArgs<T>>? KeyframeRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a data binding has been enabled
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs<T>> DataBindingEnabled;
|
||||
public event EventHandler<LayerPropertyEventArgs<T>>? DataBindingEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a data binding has been disabled
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs<T>> DataBindingDisabled;
|
||||
public event EventHandler<LayerPropertyEventArgs<T>>? DataBindingDisabled;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="Updated" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnUpdated()
|
||||
{
|
||||
Updated?.Invoke(this, new LayerPropertyEventArgs<T>(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="CurrentValueSet" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnCurrentValueSet()
|
||||
{
|
||||
CurrentValueSet?.Invoke(this, new LayerPropertyEventArgs<T>(this));
|
||||
LayerPropertyGroup.OnLayerPropertyOnCurrentValueSet(new LayerPropertyEventArgs(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="VisibilityChanged" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnVisibilityChanged()
|
||||
{
|
||||
VisibilityChanged?.Invoke(this, new LayerPropertyEventArgs<T>(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="KeyframesToggled" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnKeyframesToggled()
|
||||
{
|
||||
KeyframesToggled?.Invoke(this, new LayerPropertyEventArgs<T>(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="KeyframeAdded" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnKeyframeAdded()
|
||||
{
|
||||
KeyframeAdded?.Invoke(this, new LayerPropertyEventArgs<T>(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="KeyframeRemoved" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnKeyframeRemoved()
|
||||
{
|
||||
KeyframeRemoved?.Invoke(this, new LayerPropertyEventArgs<T>(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DataBindingEnabled" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDataBindingEnabled(LayerPropertyEventArgs<T> e)
|
||||
{
|
||||
DataBindingEnabled?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DataBindingDisabled" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDataBindingDisabled(LayerPropertyEventArgs<T> e)
|
||||
{
|
||||
DataBindingDisabled?.Invoke(this, e);
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace Artemis.Core
|
||||
public LayerPropertyKeyframe(T value, TimeSpan position, Easings.Functions easingFunction, LayerProperty<T> layerProperty)
|
||||
{
|
||||
_position = position;
|
||||
_layerProperty = layerProperty;
|
||||
_value = value;
|
||||
|
||||
Value = value;
|
||||
LayerProperty = layerProperty;
|
||||
EasingFunction = easingFunction;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,13 @@ using Humanizer;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a property group on a layer
|
||||
/// <para>
|
||||
/// Note: You cannot initialize property groups yourself. If properly placed and annotated, the Artemis core will
|
||||
/// initialize these for you.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract class LayerPropertyGroup : IDisposable
|
||||
{
|
||||
private readonly List<ILayerProperty> _layerProperties;
|
||||
@@ -18,6 +25,9 @@ namespace Artemis.Core
|
||||
private bool _disposed;
|
||||
private bool _isHidden;
|
||||
|
||||
/// <summary>
|
||||
/// A base constructor for a <see cref="LayerPropertyGroup" />
|
||||
/// </summary>
|
||||
protected LayerPropertyGroup()
|
||||
{
|
||||
_layerProperties = new List<ILayerProperty>();
|
||||
@@ -28,7 +38,7 @@ namespace Artemis.Core
|
||||
/// Gets the description of this group
|
||||
/// </summary>
|
||||
public PropertyGroupDescriptionAttribute GroupDescription { get; internal set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin feature this group is associated with
|
||||
/// </summary>
|
||||
@@ -87,22 +97,6 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<LayerPropertyGroup> LayerPropertyGroups => _layerPropertyGroups.AsReadOnly();
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_disposed = true;
|
||||
DisableProperties();
|
||||
|
||||
foreach (ILayerProperty layerProperty in _layerProperties)
|
||||
layerProperty.Dispose();
|
||||
foreach (LayerPropertyGroup layerPropertyGroup in _layerPropertyGroups)
|
||||
layerPropertyGroup.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Recursively gets all layer properties on this group and any subgroups
|
||||
/// </summary>
|
||||
@@ -165,7 +159,9 @@ namespace Artemis.Core
|
||||
{
|
||||
Attribute? propertyDescription = Attribute.GetCustomAttribute(propertyInfo, typeof(PropertyDescriptionAttribute));
|
||||
if (propertyDescription != null)
|
||||
{
|
||||
InitializeProperty(propertyInfo, (PropertyDescriptionAttribute) propertyDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
Attribute? propertyGroupDescription = Attribute.GetCustomAttribute(propertyInfo, typeof(PropertyGroupDescriptionAttribute));
|
||||
@@ -265,6 +261,22 @@ namespace Artemis.Core
|
||||
return entity;
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_disposed = true;
|
||||
DisableProperties();
|
||||
|
||||
foreach (ILayerProperty layerProperty in _layerProperties)
|
||||
layerProperty.Dispose();
|
||||
foreach (LayerPropertyGroup layerPropertyGroup in _layerPropertyGroups)
|
||||
layerPropertyGroup.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,34 +1,57 @@
|
||||
using SkiaSharp;
|
||||
|
||||
#pragma warning disable 8618
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the transform properties of a layer
|
||||
/// </summary>
|
||||
public class LayerTransformProperties : LayerPropertyGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// The point at which the shape is attached to its position
|
||||
/// </summary>
|
||||
[PropertyDescription(Description = "The point at which the shape is attached to its position", InputStepSize = 0.001f)]
|
||||
public SKPointLayerProperty AnchorPoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The position of the shape
|
||||
/// </summary>
|
||||
[PropertyDescription(Description = "The position of the shape", InputStepSize = 0.001f)]
|
||||
public SKPointLayerProperty Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The scale of the shape
|
||||
/// </summary>
|
||||
[PropertyDescription(Description = "The scale of the shape", InputAffix = "%", MinInputValue = 0f)]
|
||||
public SKSizeLayerProperty Scale { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The rotation of the shape in degree
|
||||
/// </summary>
|
||||
[PropertyDescription(Description = "The rotation of the shape in degrees", InputAffix = "°")]
|
||||
public FloatLayerProperty Rotation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The opacity of the shape
|
||||
/// </summary>
|
||||
[PropertyDescription(Description = "The opacity of the shape", InputAffix = "%", MinInputValue = 0f, MaxInputValue = 100f)]
|
||||
public FloatLayerProperty Opacity { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void PopulateDefaults()
|
||||
{
|
||||
Scale.DefaultValue = new SKSize(100, 100);
|
||||
Opacity.DefaultValue = 100;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void EnableProperties()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DisableProperties()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a profile containing folders and layers
|
||||
/// </summary>
|
||||
public sealed class Profile : ProfileElement
|
||||
{
|
||||
private bool _isActivated;
|
||||
@@ -39,8 +42,14 @@ namespace Artemis.Core
|
||||
Load();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the module backing this profile
|
||||
/// </summary>
|
||||
public ProfileModule Module { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether this profile is activated
|
||||
/// </summary>
|
||||
public bool IsActivated
|
||||
{
|
||||
get => _isActivated;
|
||||
@@ -52,6 +61,7 @@ namespace Artemis.Core
|
||||
internal Stack<string> UndoStack { get; set; }
|
||||
internal Stack<string> RedoStack { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
lock (this)
|
||||
@@ -66,6 +76,7 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Render(SKCanvas canvas)
|
||||
{
|
||||
lock (this)
|
||||
@@ -87,6 +98,11 @@ namespace Artemis.Core
|
||||
child.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the root folder of this profile
|
||||
/// </summary>
|
||||
/// <returns>The root folder of the profile</returns>
|
||||
/// <exception cref="ObjectDisposedException"></exception>
|
||||
public Folder GetRootFolder()
|
||||
{
|
||||
if (Disposed)
|
||||
@@ -95,6 +111,28 @@ namespace Artemis.Core
|
||||
return (Folder) Children.Single();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[Profile] {nameof(Name)}: {Name}, {nameof(IsActivated)}: {IsActivated}, {nameof(Module)}: {Module}";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
OnDeactivating();
|
||||
|
||||
foreach (ProfileElement profileElement in Children)
|
||||
profileElement.Dispose();
|
||||
ChildrenList.Clear();
|
||||
|
||||
IsActivated = false;
|
||||
Disposed = true;
|
||||
}
|
||||
|
||||
internal override void Load()
|
||||
{
|
||||
if (Disposed)
|
||||
@@ -116,30 +154,12 @@ namespace Artemis.Core
|
||||
Folder _ = new Folder(this, "Root folder");
|
||||
}
|
||||
else
|
||||
{
|
||||
AddChild(new Folder(this, this, rootFolder));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[Profile] {nameof(Name)}: {Name}, {nameof(IsActivated)}: {IsActivated}, {nameof(Module)}: {Module}";
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
OnDeactivating();
|
||||
|
||||
foreach (ProfileElement profileElement in Children)
|
||||
profileElement.Dispose();
|
||||
ChildrenList.Clear();
|
||||
|
||||
IsActivated = false;
|
||||
Disposed = true;
|
||||
}
|
||||
|
||||
internal override void Save()
|
||||
{
|
||||
if (Disposed)
|
||||
@@ -189,12 +209,12 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Occurs when the profile has been activated.
|
||||
/// </summary>
|
||||
public event EventHandler Activated;
|
||||
public event EventHandler? Activated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the profile is being deactivated.
|
||||
/// </summary>
|
||||
public event EventHandler Deactivated;
|
||||
public event EventHandler? Deactivated;
|
||||
|
||||
private void OnActivated()
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@ using Artemis.Storage.Entities.Profile;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a descriptor that describes a profile
|
||||
/// </summary>
|
||||
public class ProfileDescriptor
|
||||
{
|
||||
internal ProfileDescriptor(ProfileModule profileModule, ProfileEntity profileEntity)
|
||||
@@ -15,10 +18,24 @@ namespace Artemis.Core
|
||||
IsLastActiveProfile = profileEntity.IsActive;
|
||||
}
|
||||
|
||||
public bool IsLastActiveProfile { get; set; }
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether this was the last active profile
|
||||
/// </summary>
|
||||
public bool IsLastActiveProfile { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique ID of the profile by which it can be loaded from storage
|
||||
/// </summary>
|
||||
public Guid Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the module backing the profile
|
||||
/// </summary>
|
||||
public ProfileModule ProfileModule { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the profile
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
}
|
||||
}
|
||||
@@ -6,18 +6,22 @@ using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an element of a <see cref="Profile" />
|
||||
/// </summary>
|
||||
public abstract class ProfileElement : CorePropertyChanged, IDisposable
|
||||
{
|
||||
private bool _enabled;
|
||||
private Guid _entityId;
|
||||
private string _name;
|
||||
private int _order;
|
||||
private ProfileElement _parent;
|
||||
private ProfileElement? _parent;
|
||||
private Profile _profile;
|
||||
protected List<ProfileElement> ChildrenList;
|
||||
protected bool Disposed;
|
||||
|
||||
protected ProfileElement()
|
||||
internal List<ProfileElement> ChildrenList;
|
||||
internal bool Disposed;
|
||||
|
||||
internal ProfileElement()
|
||||
{
|
||||
ChildrenList = new List<ProfileElement>();
|
||||
}
|
||||
@@ -43,7 +47,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets the parent of this element
|
||||
/// </summary>
|
||||
public ProfileElement Parent
|
||||
public ProfileElement? Parent
|
||||
{
|
||||
get => _parent;
|
||||
internal set => SetAndNotify(ref _parent, value);
|
||||
@@ -233,6 +237,9 @@ namespace Artemis.Core
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the profile element
|
||||
/// </summary>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
@@ -244,14 +251,27 @@ namespace Artemis.Core
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler ChildAdded;
|
||||
public event EventHandler ChildRemoved;
|
||||
/// <summary>
|
||||
/// Occurs when a child was added to the <see cref="Children" /> list
|
||||
/// </summary>
|
||||
public event EventHandler? ChildAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a child was removed from the <see cref="Children" /> list
|
||||
/// </summary>
|
||||
public event EventHandler? ChildRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="ChildAdded" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnChildAdded()
|
||||
{
|
||||
ChildAdded?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="ChildRemoved" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnChildRemoved()
|
||||
{
|
||||
ChildRemoved?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Artemis.Core
|
||||
{
|
||||
public abstract class PropertiesProfileElement : ProfileElement
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,12 @@ using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an element of a <see cref="Profile" /> that has advanced rendering capabilities
|
||||
/// </summary>
|
||||
public abstract class RenderProfileElement : ProfileElement
|
||||
{
|
||||
protected RenderProfileElement()
|
||||
internal RenderProfileElement()
|
||||
{
|
||||
Timeline = new Timeline();
|
||||
Renderer = new Renderer();
|
||||
@@ -22,8 +25,28 @@ namespace Artemis.Core
|
||||
LayerEffectStore.LayerEffectRemoved += LayerEffectStoreOnLayerEffectRemoved;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a list of all layer properties present on this render element
|
||||
/// </summary>
|
||||
/// <returns>A list of all layer properties present on this render element</returns>
|
||||
public abstract List<ILayerProperty> GetAllLayerProperties();
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
LayerEffectStore.LayerEffectAdded -= LayerEffectStoreOnLayerEffectAdded;
|
||||
LayerEffectStore.LayerEffectRemoved -= LayerEffectStoreOnLayerEffectRemoved;
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||
baseLayerEffect.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal void LoadRenderElement()
|
||||
{
|
||||
DisplayCondition = RenderElementEntity.DisplayCondition != null
|
||||
@@ -73,7 +96,8 @@ namespace Artemis.Core
|
||||
public Timeline Timeline { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates the <see cref="Timeline"/> according to the provided <paramref name="deltaTime"/> and current display condition status
|
||||
/// Updates the <see cref="Timeline" /> according to the provided <paramref name="deltaTime" /> and current display
|
||||
/// condition status
|
||||
/// </summary>
|
||||
public void UpdateTimeline(double deltaTime)
|
||||
{
|
||||
@@ -86,31 +110,16 @@ namespace Artemis.Core
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
LayerEffectStore.LayerEffectAdded -= LayerEffectStoreOnLayerEffectAdded;
|
||||
LayerEffectStore.LayerEffectRemoved -= LayerEffectStoreOnLayerEffectRemoved;
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||
baseLayerEffect.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
private ProfileElement _parent;
|
||||
private SKPath _path;
|
||||
private ProfileElement? _parent;
|
||||
private SKPath? _path;
|
||||
internal abstract RenderElementEntity RenderElementEntity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent of this element
|
||||
/// </summary>
|
||||
public new ProfileElement Parent
|
||||
public new ProfileElement? Parent
|
||||
{
|
||||
get => _parent;
|
||||
internal set
|
||||
@@ -124,7 +133,7 @@ namespace Artemis.Core
|
||||
/// Gets the path containing all the LEDs this entity is applied to, any rendering outside the entity Path is
|
||||
/// clipped.
|
||||
/// </summary>
|
||||
public SKPath Path
|
||||
public SKPath? Path
|
||||
{
|
||||
get => _path;
|
||||
protected set
|
||||
@@ -150,20 +159,30 @@ namespace Artemis.Core
|
||||
|
||||
#region Property group expansion
|
||||
|
||||
protected List<string> _expandedPropertyGroups;
|
||||
internal List<string> ExpandedPropertyGroups;
|
||||
private SKRect _bounds;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided property group is expanded
|
||||
/// </summary>
|
||||
/// <param name="layerPropertyGroup">The property group to check</param>
|
||||
/// <returns>A boolean indicating whether the provided property group is expanded</returns>
|
||||
public bool IsPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup)
|
||||
{
|
||||
return _expandedPropertyGroups.Contains(layerPropertyGroup.Path);
|
||||
return ExpandedPropertyGroups.Contains(layerPropertyGroup.Path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expands or collapses the provided property group
|
||||
/// </summary>
|
||||
/// <param name="layerPropertyGroup">The group to expand or collapse</param>
|
||||
/// <param name="expanded">Whether to expand or collapse the property group</param>
|
||||
public void SetPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup, bool expanded)
|
||||
{
|
||||
if (!expanded && IsPropertyGroupExpanded(layerPropertyGroup))
|
||||
_expandedPropertyGroups.Remove(layerPropertyGroup.Path);
|
||||
ExpandedPropertyGroups.Remove(layerPropertyGroup.Path);
|
||||
else if (expanded && !IsPropertyGroupExpanded(layerPropertyGroup))
|
||||
_expandedPropertyGroups.Add(layerPropertyGroup.Path);
|
||||
ExpandedPropertyGroups.Add(layerPropertyGroup.Path);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -172,12 +191,12 @@ namespace Artemis.Core
|
||||
|
||||
#region Effect management
|
||||
|
||||
protected List<BaseLayerEffect> _layerEffects;
|
||||
internal List<BaseLayerEffect> LayerEffectsList;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read-only collection of the layer effects on this entity
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<BaseLayerEffect> LayerEffects => _layerEffects.AsReadOnly();
|
||||
public ReadOnlyCollection<BaseLayerEffect> LayerEffects => LayerEffectsList.AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a the layer effect described inthe provided <paramref name="descriptor" />
|
||||
@@ -208,7 +227,7 @@ namespace Artemis.Core
|
||||
if (effect == null) throw new ArgumentNullException(nameof(effect));
|
||||
|
||||
// Remove the effect from the layer and dispose it
|
||||
_layerEffects.Remove(effect);
|
||||
LayerEffectsList.Remove(effect);
|
||||
effect.Dispose();
|
||||
|
||||
// Update the order on the remaining effects
|
||||
@@ -225,7 +244,7 @@ namespace Artemis.Core
|
||||
index++;
|
||||
}
|
||||
|
||||
_layerEffects.Sort((a, b) => a.Order.CompareTo(b.Order));
|
||||
LayerEffectsList.Sort((a, b) => a.Order.CompareTo(b.Order));
|
||||
}
|
||||
|
||||
internal void ActivateEffects()
|
||||
@@ -233,7 +252,7 @@ namespace Artemis.Core
|
||||
foreach (LayerEffectEntity layerEffectEntity in RenderElementEntity.LayerEffects)
|
||||
{
|
||||
// If there is a non-placeholder existing effect, skip this entity
|
||||
BaseLayerEffect? existing = _layerEffects.FirstOrDefault(e => e.EntityId == layerEffectEntity.Id);
|
||||
BaseLayerEffect? existing = LayerEffectsList.FirstOrDefault(e => e.EntityId == layerEffectEntity.Id);
|
||||
if (existing != null && existing.Descriptor.PlaceholderFor == null)
|
||||
continue;
|
||||
|
||||
@@ -243,7 +262,7 @@ namespace Artemis.Core
|
||||
// If a descriptor is found but there is an existing placeholder, remove the placeholder
|
||||
if (existing != null)
|
||||
{
|
||||
_layerEffects.Remove(existing);
|
||||
LayerEffectsList.Remove(existing);
|
||||
existing.Dispose();
|
||||
}
|
||||
|
||||
@@ -264,19 +283,19 @@ namespace Artemis.Core
|
||||
|
||||
internal void ActivateLayerEffect(BaseLayerEffect layerEffect)
|
||||
{
|
||||
_layerEffects.Add(layerEffect);
|
||||
LayerEffectsList.Add(layerEffect);
|
||||
OnLayerEffectsUpdated();
|
||||
}
|
||||
|
||||
private void LayerEffectStoreOnLayerEffectRemoved(object sender, LayerEffectStoreEvent e)
|
||||
{
|
||||
// If effects provided by the plugin are on the element, replace them with placeholders
|
||||
List<BaseLayerEffect> pluginEffects = _layerEffects.Where(ef => ef.Descriptor.Provider != null &&
|
||||
ef.ProviderId == e.Registration.PluginFeature.Id).ToList();
|
||||
List<BaseLayerEffect> pluginEffects = LayerEffectsList.Where(ef => ef.Descriptor.Provider != null &&
|
||||
ef.ProviderId == e.Registration.PluginFeature.Id).ToList();
|
||||
foreach (BaseLayerEffect pluginEffect in pluginEffects)
|
||||
{
|
||||
LayerEffectEntity entity = RenderElementEntity.LayerEffects.First(en => en.Id == pluginEffect.EntityId);
|
||||
_layerEffects.Remove(pluginEffect);
|
||||
LayerEffectsList.Remove(pluginEffect);
|
||||
pluginEffect.Dispose();
|
||||
|
||||
LayerEffectDescriptor descriptor = PlaceholderLayerEffectDescriptor.Create(pluginEffect.ProviderId);
|
||||
@@ -317,7 +336,7 @@ namespace Artemis.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the display conditions on this element and applies any required changes to the <see cref="Timeline"/>
|
||||
/// Evaluates the display conditions on this element and applies any required changes to the <see cref="Timeline" />
|
||||
/// </summary>
|
||||
public void UpdateDisplayCondition()
|
||||
{
|
||||
@@ -344,7 +363,9 @@ namespace Artemis.Core
|
||||
{
|
||||
// Event conditions reset if the timeline finished
|
||||
if (Timeline.IsFinished)
|
||||
{
|
||||
Timeline.JumpToStart();
|
||||
}
|
||||
// and otherwise apply their overlap mode
|
||||
else
|
||||
{
|
||||
@@ -365,7 +386,10 @@ namespace Artemis.Core
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler LayerEffectsUpdated;
|
||||
/// <summary>
|
||||
/// Occurs when a layer effect has been added or removed to this render element
|
||||
/// </summary>
|
||||
public event EventHandler? LayerEffectsUpdated;
|
||||
|
||||
internal void OnLayerEffectsUpdated()
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Artemis.Core
|
||||
Bitmap = new SKBitmap(width, height);
|
||||
Path = new SKPath(path);
|
||||
Canvas = new SKCanvas(Bitmap);
|
||||
Path.Transform(SKMatrix.MakeTranslation(pathBounds.Left * -1, pathBounds.Top * -1));
|
||||
Path.Transform(SKMatrix.CreateTranslation(pathBounds.Left * -1, pathBounds.Top * -1));
|
||||
|
||||
TargetLocation = new SKPoint(pathBounds.Location.X, pathBounds.Location.Y);
|
||||
if (parent != null)
|
||||
|
||||
@@ -429,6 +429,7 @@ namespace Artemis.Core
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Progress: {Position}/{Length} - delta: {Delta}";
|
||||
|
||||
Reference in new issue
Block a user