mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +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:
parent
61fc96742d
commit
a3cd32f6c4
@ -13,6 +13,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<DocumentationFile>bin\x64\Debug\Artemis.Core.xml</DocumentationFile>
|
||||
<NoWarn>1701;1702</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@ -39,9 +39,9 @@ namespace Artemis.Core
|
||||
if (ValueTypeSetExpression == null)
|
||||
return;
|
||||
|
||||
if (DataBinding.LayerProperty.PropertyDescription.MaxInputValue is float max)
|
||||
if (DataBinding!.LayerProperty.PropertyDescription.MaxInputValue is float max)
|
||||
value = Math.Min(value, max);
|
||||
if (DataBinding.LayerProperty.PropertyDescription.MinInputValue is float min)
|
||||
if (DataBinding!.LayerProperty.PropertyDescription.MinInputValue is float min)
|
||||
value = Math.Max(value, min);
|
||||
|
||||
base.ApplyValue(value);
|
||||
|
||||
@ -5,6 +5,9 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
public class SKColorDataBindingConverter : DataBindingConverter<SKColor, SKColor>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="SKColorDataBindingConverter" /> class
|
||||
/// </summary>
|
||||
public SKColorDataBindingConverter()
|
||||
{
|
||||
SupportsInterpolate = true;
|
||||
|
||||
@ -5,7 +5,7 @@ namespace Artemis.Core
|
||||
internal class CosecantModifierType : DataBindingModifierType<double>
|
||||
{
|
||||
public override string Name => "Cosecant";
|
||||
public override string Icon => null;
|
||||
public override string? Icon => null;
|
||||
public override string Category => "Trigonometry";
|
||||
public override string Description => "Treats the input as an angle and calculates the cosecant";
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ namespace Artemis.Core
|
||||
internal class CotangentModifierType : DataBindingModifierType<double>
|
||||
{
|
||||
public override string Name => "Cotangent";
|
||||
public override string Icon => null;
|
||||
public override string? Icon => null;
|
||||
public override string Category => "Trigonometry";
|
||||
public override string Description => "Treats the input as an angle and calculates the cotangent";
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ namespace Artemis.Core
|
||||
internal class SecantModifierType : DataBindingModifierType<double>
|
||||
{
|
||||
public override string Name => "Secant";
|
||||
public override string Icon => null;
|
||||
public override string? Icon => null;
|
||||
public override string Category => "Trigonometry";
|
||||
public override string Description => "Treats the input as an angle and calculates the secant";
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
throw new ArtemisCoreException("Color Gradients do not support keyframes.");
|
||||
}
|
||||
|
||||
private void OnCurrentValueSet(object sender, LayerPropertyEventArgs<ColorGradient> e)
|
||||
private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs<ColorGradient> e)
|
||||
{
|
||||
// Don't allow color gradients to be null
|
||||
if (BaseValue == null)
|
||||
|
||||
@ -27,8 +27,8 @@
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
||||
{
|
||||
float diff = NextKeyframe.Value - CurrentKeyframe.Value;
|
||||
CurrentValue = CurrentKeyframe.Value + diff * keyframeProgressEased;
|
||||
float diff = NextKeyframe!.Value - CurrentKeyframe!.Value;
|
||||
CurrentValue = CurrentKeyframe!.Value + diff * keyframeProgressEased;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,15 +14,15 @@
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
||||
{
|
||||
float startDiff = NextKeyframe.Value.Start - CurrentKeyframe.Value.Start;
|
||||
float endDiff = NextKeyframe.Value.End - CurrentKeyframe.Value.End;
|
||||
float startDiff = NextKeyframe!.Value.Start - CurrentKeyframe!.Value.Start;
|
||||
float endDiff = NextKeyframe!.Value.End - CurrentKeyframe!.Value.End;
|
||||
CurrentValue = new FloatRange(
|
||||
(int) (CurrentKeyframe.Value.Start + startDiff * keyframeProgressEased),
|
||||
(int) (CurrentKeyframe.Value.End + endDiff * keyframeProgressEased)
|
||||
(int) (CurrentKeyframe!.Value.Start + startDiff * keyframeProgressEased),
|
||||
(int) (CurrentKeyframe!.Value.End + endDiff * keyframeProgressEased)
|
||||
);
|
||||
}
|
||||
|
||||
private void OnCurrentValueSet(object sender, LayerPropertyEventArgs<FloatRange> e)
|
||||
private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs<FloatRange> e)
|
||||
{
|
||||
// Don't allow the int range to be null
|
||||
BaseValue ??= DefaultValue ?? new FloatRange(0, 0);
|
||||
|
||||
@ -37,8 +37,8 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
||||
{
|
||||
int diff = NextKeyframe.Value - CurrentKeyframe.Value;
|
||||
CurrentValue = (int) Math.Round(CurrentKeyframe.Value + diff * keyframeProgressEased, MidpointRounding.AwayFromZero);
|
||||
int diff = NextKeyframe!.Value - CurrentKeyframe!.Value;
|
||||
CurrentValue = (int) Math.Round(CurrentKeyframe!.Value + diff * keyframeProgressEased, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,15 +14,15 @@
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
||||
{
|
||||
float startDiff = NextKeyframe.Value.Start - CurrentKeyframe.Value.Start;
|
||||
float endDiff = NextKeyframe.Value.End - CurrentKeyframe.Value.End;
|
||||
float startDiff = NextKeyframe!.Value.Start - CurrentKeyframe!.Value.Start;
|
||||
float endDiff = NextKeyframe!.Value.End - CurrentKeyframe!.Value.End;
|
||||
CurrentValue = new IntRange(
|
||||
(int) (CurrentKeyframe.Value.Start + startDiff * keyframeProgressEased),
|
||||
(int) (CurrentKeyframe.Value.End + endDiff * keyframeProgressEased)
|
||||
(int) (CurrentKeyframe!.Value.Start + startDiff * keyframeProgressEased),
|
||||
(int) (CurrentKeyframe!.Value.End + endDiff * keyframeProgressEased)
|
||||
);
|
||||
}
|
||||
|
||||
private void OnCurrentValueSet(object sender, LayerPropertyEventArgs<IntRange> e)
|
||||
private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs<IntRange> e)
|
||||
{
|
||||
// Don't allow the int range to be null
|
||||
BaseValue ??= DefaultValue ?? new IntRange(0, 0);
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// A special layer property used to configure the selected layer brush
|
||||
/// </summary>
|
||||
public class LayerBrushReferenceLayerProperty : LayerProperty<LayerBrushReference>
|
||||
public class LayerBrushReferenceLayerProperty : LayerProperty<LayerBrushReference?>
|
||||
{
|
||||
internal LayerBrushReferenceLayerProperty()
|
||||
{
|
||||
@ -14,7 +14,7 @@
|
||||
/// <summary>
|
||||
/// Implicitly converts an <see cref="LayerBrushReferenceLayerProperty" /> to an <see cref="LayerBrushReference" />
|
||||
/// </summary>
|
||||
public static implicit operator LayerBrushReference(LayerBrushReferenceLayerProperty p)
|
||||
public static implicit operator LayerBrushReference?(LayerBrushReferenceLayerProperty p)
|
||||
{
|
||||
return p.CurrentValue;
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
||||
{
|
||||
CurrentValue = CurrentKeyframe.Value.Interpolate(NextKeyframe.Value, keyframeProgressEased);
|
||||
CurrentValue = CurrentKeyframe!.Value.Interpolate(NextKeyframe!.Value, keyframeProgressEased);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,9 +22,9 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
||||
{
|
||||
float xDiff = NextKeyframe.Value.X - CurrentKeyframe.Value.X;
|
||||
float yDiff = NextKeyframe.Value.Y - CurrentKeyframe.Value.Y;
|
||||
CurrentValue = new SKPoint(CurrentKeyframe.Value.X + xDiff * keyframeProgressEased, CurrentKeyframe.Value.Y + yDiff * keyframeProgressEased);
|
||||
float xDiff = NextKeyframe!.Value.X - CurrentKeyframe!.Value.X;
|
||||
float yDiff = NextKeyframe!.Value.Y - CurrentKeyframe!.Value.Y;
|
||||
CurrentValue = new SKPoint(CurrentKeyframe!.Value.X + xDiff * keyframeProgressEased, CurrentKeyframe!.Value.Y + yDiff * keyframeProgressEased);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,9 +22,9 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
||||
{
|
||||
float widthDiff = NextKeyframe.Value.Width - CurrentKeyframe.Value.Width;
|
||||
float heightDiff = NextKeyframe.Value.Height - CurrentKeyframe.Value.Height;
|
||||
CurrentValue = new SKSize(CurrentKeyframe.Value.Width + widthDiff * keyframeProgressEased, CurrentKeyframe.Value.Height + heightDiff * keyframeProgressEased);
|
||||
float widthDiff = NextKeyframe!.Value.Width - CurrentKeyframe!.Value.Width;
|
||||
float heightDiff = NextKeyframe!.Value.Height - CurrentKeyframe!.Value.Height;
|
||||
CurrentValue = new SKSize(CurrentKeyframe!.Value.Width + widthDiff * keyframeProgressEased, CurrentKeyframe!.Value.Height + heightDiff * keyframeProgressEased);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,9 @@ namespace Artemis.Core
|
||||
Surface = surface;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active surface at the time the event fired
|
||||
/// </summary>
|
||||
public ArtemisSurface Surface { get; }
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,9 @@ namespace Artemis.Core
|
||||
Device = device;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device this event is related to
|
||||
/// </summary>
|
||||
public IRGBDevice Device { get; }
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,14 @@ namespace Artemis.Core
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dynamic data model
|
||||
/// </summary>
|
||||
public DataModel DynamicDataModel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key of the dynamic data model on the parent <see cref="DataModel" />
|
||||
/// </summary>
|
||||
public string Key { get; }
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,14 @@ namespace Artemis.Core
|
||||
RgbSurface = rgbSurface;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitmap brush used to render this frame
|
||||
/// </summary>
|
||||
public BitmapBrush BitmapBrush { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RGB surface used to render this frame
|
||||
/// </summary>
|
||||
public RGBSurface RgbSurface { get; }
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Core.Modules;
|
||||
using RGB.NET.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
@ -11,17 +9,26 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public class FrameRenderingEventArgs : EventArgs
|
||||
{
|
||||
internal FrameRenderingEventArgs(List<Module> modules, SKCanvas canvas, double deltaTime, RGBSurface rgbSurface)
|
||||
internal FrameRenderingEventArgs(SKCanvas canvas, double deltaTime, RGBSurface rgbSurface)
|
||||
{
|
||||
Modules = modules;
|
||||
Canvas = canvas;
|
||||
DeltaTime = deltaTime;
|
||||
RgbSurface = rgbSurface;
|
||||
}
|
||||
|
||||
public List<Module> Modules { get; }
|
||||
/// <summary>
|
||||
/// Gets the canvas this frame is rendering on
|
||||
/// </summary>
|
||||
public SKCanvas Canvas { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the delta time since the last frame was rendered
|
||||
/// </summary>
|
||||
public double DeltaTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RGB surface used to render this frame
|
||||
/// </summary>
|
||||
public RGBSurface RgbSurface { get; }
|
||||
}
|
||||
}
|
||||
@ -2,17 +2,19 @@
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides data about plugin related events
|
||||
/// </summary>
|
||||
public class PluginEventArgs : EventArgs
|
||||
{
|
||||
public PluginEventArgs()
|
||||
{
|
||||
}
|
||||
|
||||
public PluginEventArgs(Plugin plugin)
|
||||
internal PluginEventArgs(Plugin plugin)
|
||||
{
|
||||
Plugin = plugin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin this event is related to
|
||||
/// </summary>
|
||||
public Plugin Plugin { get; }
|
||||
}
|
||||
}
|
||||
@ -2,17 +2,19 @@
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides data about plugin feature related events
|
||||
/// </summary>
|
||||
public class PluginFeatureEventArgs : EventArgs
|
||||
{
|
||||
public PluginFeatureEventArgs()
|
||||
{
|
||||
}
|
||||
|
||||
public PluginFeatureEventArgs(PluginFeature pluginFeature)
|
||||
internal PluginFeatureEventArgs(PluginFeature pluginFeature)
|
||||
{
|
||||
PluginFeature = pluginFeature;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin feature this event is related to
|
||||
/// </summary>
|
||||
public PluginFeature PluginFeature { get; }
|
||||
}
|
||||
}
|
||||
@ -2,9 +2,13 @@
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides data for the <see langword='DataBindingPropertyUpdatedEvent' /> event.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class DataBindingPropertyUpdatedEvent<T> : EventArgs
|
||||
{
|
||||
public DataBindingPropertyUpdatedEvent(T value)
|
||||
internal DataBindingPropertyUpdatedEvent(T value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
@ -2,23 +2,35 @@
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides strongly typed data for layer property events of type <typeparamref name="T" />.
|
||||
/// </summary>
|
||||
public class LayerPropertyEventArgs<T> : EventArgs
|
||||
{
|
||||
public LayerPropertyEventArgs(LayerProperty<T> layerProperty)
|
||||
internal LayerPropertyEventArgs(LayerProperty<T> layerProperty)
|
||||
{
|
||||
LayerProperty = layerProperty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layer property this event is related to
|
||||
/// </summary>
|
||||
public LayerProperty<T> LayerProperty { get; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides data for layer property events.
|
||||
/// </summary>
|
||||
public class LayerPropertyEventArgs : EventArgs
|
||||
{
|
||||
public LayerPropertyEventArgs(ILayerProperty layerProperty)
|
||||
internal LayerPropertyEventArgs(ILayerProperty layerProperty)
|
||||
{
|
||||
LayerProperty = layerProperty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layer property this event is related to
|
||||
/// </summary>
|
||||
public ILayerProperty LayerProperty { get; }
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
public class LayerPropertyGroupUpdatingEventArgs : EventArgs
|
||||
{
|
||||
public LayerPropertyGroupUpdatingEventArgs(double deltaTime)
|
||||
{
|
||||
DeltaTime = deltaTime;
|
||||
}
|
||||
|
||||
public double DeltaTime { get; }
|
||||
}
|
||||
}
|
||||
@ -2,31 +2,37 @@
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception thrown when a plugin-related error occurs
|
||||
/// </summary>
|
||||
public class ArtemisPluginException : Exception
|
||||
{
|
||||
public ArtemisPluginException(Plugin plugin)
|
||||
internal ArtemisPluginException(Plugin plugin)
|
||||
{
|
||||
Plugin = plugin;
|
||||
}
|
||||
|
||||
public ArtemisPluginException(Plugin plugin, string message) : base(message)
|
||||
internal ArtemisPluginException(Plugin plugin, string message) : base(message)
|
||||
{
|
||||
Plugin = plugin;
|
||||
}
|
||||
|
||||
public ArtemisPluginException(Plugin plugin, string message, Exception inner) : base(message, inner)
|
||||
internal ArtemisPluginException(Plugin plugin, string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
Plugin = plugin;
|
||||
}
|
||||
|
||||
public ArtemisPluginException(string message) : base(message)
|
||||
internal ArtemisPluginException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ArtemisPluginException(string message, Exception inner) : base(message, inner)
|
||||
internal ArtemisPluginException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
}
|
||||
|
||||
public Plugin Plugin { get; }
|
||||
/// <summary>
|
||||
/// Gets the plugin the error is related to
|
||||
/// </summary>
|
||||
public Plugin? Plugin { get; }
|
||||
}
|
||||
}
|
||||
@ -2,23 +2,29 @@
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception thrown when a plugin feature-related error occurs
|
||||
/// </summary>
|
||||
public class ArtemisPluginFeatureException : Exception
|
||||
{
|
||||
internal ArtemisPluginFeatureException(PluginFeature pluginFeature)
|
||||
{
|
||||
PluginFeature = pluginFeature;
|
||||
}
|
||||
|
||||
internal ArtemisPluginFeatureException(PluginFeature pluginFeature, string message) : base(message)
|
||||
{
|
||||
PluginFeature = pluginFeature;
|
||||
}
|
||||
|
||||
internal ArtemisPluginFeatureException(PluginFeature pluginFeature, string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
PluginFeature = pluginFeature;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin feature the error is related to
|
||||
/// </summary>
|
||||
public PluginFeature PluginFeature { get; }
|
||||
|
||||
public ArtemisPluginFeatureException(PluginFeature pluginFeature)
|
||||
{
|
||||
PluginFeature = pluginFeature;
|
||||
}
|
||||
|
||||
public ArtemisPluginFeatureException(PluginFeature pluginFeature, string message) : base(message)
|
||||
{
|
||||
PluginFeature = pluginFeature;
|
||||
}
|
||||
|
||||
public ArtemisPluginFeatureException(PluginFeature pluginFeature, string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
PluginFeature = pluginFeature;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,13 +2,16 @@
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception thrown when a plugin lock file error occurs
|
||||
/// </summary>
|
||||
public class ArtemisPluginLockException : Exception
|
||||
{
|
||||
public ArtemisPluginLockException(Exception innerException) : base(CreateExceptionMessage(innerException), innerException)
|
||||
internal ArtemisPluginLockException(Exception? innerException) : base(CreateExceptionMessage(innerException), innerException)
|
||||
{
|
||||
}
|
||||
|
||||
private static string CreateExceptionMessage(Exception innerException)
|
||||
private static string CreateExceptionMessage(Exception? innerException)
|
||||
{
|
||||
return innerException != null
|
||||
? "Found a lock file, skipping load, see inner exception for last known exception."
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
public static class DirectoryInfoExtensions
|
||||
internal static class DirectoryInfoExtensions
|
||||
{
|
||||
public static void CopyFilesRecursively(this DirectoryInfo source, DirectoryInfo target)
|
||||
{
|
||||
|
||||
@ -3,8 +3,16 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A static class providing <see cref="double" /> extensions
|
||||
/// </summary>
|
||||
public static class DoubleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Rounds the provided number away to zero and casts the result to an <see cref="int" />
|
||||
/// </summary>
|
||||
/// <param name="number">The number to round</param>
|
||||
/// <returns>The rounded number as an integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int RoundToInt(this double number)
|
||||
{
|
||||
|
||||
@ -1,9 +1,19 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A static class providing <see cref="float" /> extensions
|
||||
/// </summary>
|
||||
public static class FloatExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Rounds the provided number away to zero and casts the result to an <see cref="int" />
|
||||
/// </summary>
|
||||
/// <param name="number">The number to round</param>
|
||||
/// <returns>The rounded number as an integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int RoundToInt(this float number)
|
||||
{
|
||||
return (int) Math.Round(number, MidpointRounding.AwayFromZero);
|
||||
|
||||
@ -24,6 +24,10 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A static class providing <see cref="IEnumerable{T}" /> extensions
|
||||
/// </summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static class IEnumerableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
@ -46,7 +50,7 @@ namespace Artemis.Core
|
||||
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
|
||||
Func<TSource, TKey> keySelector)
|
||||
{
|
||||
return source.DistinctBy(keySelector, null);
|
||||
return source.DistinctBy(keySelector, null!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -5,8 +5,16 @@ using System.Text;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A static class providing <see cref="Process" /> extensions
|
||||
/// </summary>
|
||||
public static class ProcessExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the file name of the given process
|
||||
/// </summary>
|
||||
/// <param name="p">The process</param>
|
||||
/// <returns>The filename of the given process</returns>
|
||||
public static string GetProcessFilename(this Process p)
|
||||
{
|
||||
int capacity = 2000;
|
||||
@ -17,7 +25,7 @@ namespace Artemis.Core
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern bool QueryFullProcessImageName([In] IntPtr hProcess, [In] int dwFlags, [Out] StringBuilder lpExeName, ref int lpdwSize);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
|
||||
@ -3,7 +3,7 @@ using RGB.NET.Core;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
public static class RgbDeviceExtensions
|
||||
internal static class RgbDeviceExtensions
|
||||
{
|
||||
public static string GetDeviceIdentifier(this IRGBDevice rgbDevice)
|
||||
{
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
using RGB.NET.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
public static class RgbRectangleExtensions
|
||||
{
|
||||
public static SKRect ToSKRect(this Rectangle rectangle, double scale)
|
||||
{
|
||||
return SKRect.Create(
|
||||
(rectangle.Location.X * scale).RoundToInt(),
|
||||
(rectangle.Location.Y * scale).RoundToInt(),
|
||||
(rectangle.Size.Width * scale).RoundToInt(),
|
||||
(rectangle.Size.Height * scale).RoundToInt()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,14 +4,28 @@ using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming - I didn't come up with SKColor
|
||||
/// <summary>
|
||||
/// A static class providing <see cref="SKColor" /> extensions
|
||||
/// </summary>
|
||||
public static class SKColorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts hte SKColor to an RGB.NET color
|
||||
/// </summary>
|
||||
/// <param name="color">The color to convert</param>
|
||||
/// <returns>The RGB.NET color</returns>
|
||||
public static Color ToRgbColor(this SKColor color)
|
||||
{
|
||||
return new Color(color.Alpha, color.Red, color.Green, color.Blue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interpolates a color between the <paramref name="from" /> and <paramref name="to" /> color.
|
||||
/// </summary>
|
||||
/// <param name="from">The first color</param>
|
||||
/// <param name="to">The second color</param>
|
||||
/// <param name="progress">A value between 0 and 1</param>
|
||||
/// <returns>The interpolated color</returns>
|
||||
public static SKColor Interpolate(this SKColor from, SKColor to, float progress)
|
||||
{
|
||||
int redDiff = to.Red - from.Red;
|
||||
@ -27,6 +41,12 @@ namespace Artemis.Core
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the two colors together
|
||||
/// </summary>
|
||||
/// <param name="a">The first color</param>
|
||||
/// <param name="b">The second color</param>
|
||||
/// <returns>The sum of the two colors</returns>
|
||||
public static SKColor Sum(this SKColor a, SKColor b)
|
||||
{
|
||||
return new SKColor(
|
||||
|
||||
@ -6,6 +6,9 @@ using Humanizer;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A static class providing <see cref="Type" /> extensions
|
||||
/// </summary>
|
||||
public static class TypeExtensions
|
||||
{
|
||||
private static readonly Dictionary<Type, List<Type>> PrimitiveTypeConversions = new Dictionary<Type, List<Type>>
|
||||
@ -40,6 +43,12 @@ namespace Artemis.Core
|
||||
{typeof(string), "string"}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided type is of a specified generic type
|
||||
/// </summary>
|
||||
/// <param name="type">The type to check</param>
|
||||
/// <param name="genericType">The generic type to match</param>
|
||||
/// <returns>True if the <paramref name="type" /> is generic and of generic type <paramref name="genericType" /></returns>
|
||||
public static bool IsGenericType(this Type type, Type genericType)
|
||||
{
|
||||
if (type == null)
|
||||
@ -48,11 +57,21 @@ namespace Artemis.Core
|
||||
return type.BaseType?.GetGenericTypeDefinition() == genericType;
|
||||
}
|
||||
|
||||
public static bool IsStruct(this Type source)
|
||||
/// <summary>
|
||||
/// Determines whether the provided type is a struct
|
||||
/// </summary>
|
||||
/// <param name="type">The type to check</param>
|
||||
/// <returns><see langword="true" /> if the type is a struct, otherwise <see langword="false" /></returns>
|
||||
public static bool IsStruct(this Type type)
|
||||
{
|
||||
return source.IsValueType && !source.IsPrimitive && !source.IsEnum;
|
||||
return type.IsValueType && !type.IsPrimitive && !type.IsEnum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided type is any kind of numeric type
|
||||
/// </summary>
|
||||
/// <param name="type">The type to check</param>
|
||||
/// <returns><see langword="true" /> if the type a numeric type, otherwise <see langword="false" /></returns>
|
||||
public static bool TypeIsNumber(this Type type)
|
||||
{
|
||||
return type == typeof(sbyte)
|
||||
@ -68,6 +87,11 @@ namespace Artemis.Core
|
||||
|| type == typeof(decimal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided value is any kind of numeric type
|
||||
/// </summary>
|
||||
/// <param name="value">The value to check</param>
|
||||
/// <returns><see langword="true" /> if the value is of a numeric type, otherwise <see langword="false" /></returns>
|
||||
public static bool IsNumber(this object value)
|
||||
{
|
||||
return value is sbyte
|
||||
@ -126,7 +150,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Returns the default value of the given type
|
||||
/// </summary>
|
||||
public static object GetDefault(this Type type)
|
||||
public static object? GetDefault(this Type type)
|
||||
{
|
||||
return type.IsValueType ? Activator.CreateInstance(type) : null;
|
||||
}
|
||||
@ -157,7 +181,7 @@ namespace Artemis.Core
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
||||
return type.GenericTypeArguments[0];
|
||||
|
||||
Type enumerableType = type.GetInterfaces().FirstOrDefault(x =>
|
||||
Type? enumerableType = type.GetInterfaces().FirstOrDefault(x =>
|
||||
x.IsGenericType &&
|
||||
x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
|
||||
|
||||
|
||||
@ -18,7 +18,9 @@ namespace Artemis.Core.JsonConverters
|
||||
|
||||
public override int ReadJson(JsonReader reader, Type objectType, int existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
{
|
||||
JValue jsonValue = serializer.Deserialize<JValue>(reader);
|
||||
JValue? jsonValue = serializer.Deserialize<JValue>(reader);
|
||||
if (jsonValue == null)
|
||||
throw new FormatException();
|
||||
|
||||
if (jsonValue.Type == JTokenType.Float)
|
||||
return (int) Math.Round(jsonValue.Value<double>());
|
||||
|
||||
@ -13,7 +13,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Occurs when a property value changes.
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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}";
|
||||
|
||||
@ -1,22 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core.DeviceProviders;
|
||||
using Artemis.Storage.Entities.Surface;
|
||||
using RGB.NET.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an RGB device usable by Artemis, provided by a <see cref="DeviceProviders.DeviceProvider" />
|
||||
/// </summary>
|
||||
public class ArtemisDevice : CorePropertyChanged
|
||||
{
|
||||
private ReadOnlyCollection<ArtemisLed> _leds;
|
||||
private SKPath _renderPath;
|
||||
private SKRect _renderRectangle;
|
||||
|
||||
internal ArtemisDevice(IRGBDevice rgbDevice, PluginFeature pluginFeature, ArtemisSurface surface)
|
||||
internal ArtemisDevice(IRGBDevice rgbDevice, DeviceProvider deviceProvider, ArtemisSurface surface)
|
||||
{
|
||||
RgbDevice = rgbDevice;
|
||||
PluginFeature = pluginFeature;
|
||||
DeviceProvider = deviceProvider;
|
||||
Surface = surface;
|
||||
DeviceEntity = new DeviceEntity();
|
||||
Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||
@ -29,38 +33,60 @@ namespace Artemis.Core
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
|
||||
internal ArtemisDevice(IRGBDevice rgbDevice, PluginFeature pluginFeature, ArtemisSurface surface, DeviceEntity deviceEntity)
|
||||
internal ArtemisDevice(IRGBDevice rgbDevice, DeviceProvider deviceProvider, ArtemisSurface surface, DeviceEntity deviceEntity)
|
||||
{
|
||||
RgbDevice = rgbDevice;
|
||||
PluginFeature = pluginFeature;
|
||||
DeviceProvider = deviceProvider;
|
||||
Surface = surface;
|
||||
DeviceEntity = deviceEntity;
|
||||
Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rectangle covering the device, sized to match the render scale
|
||||
/// </summary>
|
||||
public SKRect RenderRectangle
|
||||
{
|
||||
get => _renderRectangle;
|
||||
private set => SetAndNotify(ref _renderRectangle, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path surrounding the device, sized to match the render scale
|
||||
/// </summary>
|
||||
public SKPath RenderPath
|
||||
{
|
||||
get => _renderPath;
|
||||
private set => SetAndNotify(ref _renderPath, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RGB.NET device backing this Artemis device
|
||||
/// </summary>
|
||||
public IRGBDevice RgbDevice { get; }
|
||||
public PluginFeature PluginFeature { get; }
|
||||
public ArtemisSurface Surface { get; }
|
||||
public DeviceEntity DeviceEntity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device provider that provided this device
|
||||
/// </summary>
|
||||
public DeviceProvider DeviceProvider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the surface containing this device
|
||||
/// </summary>
|
||||
public ArtemisSurface Surface { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read only collection containing the LEDs of this device
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<ArtemisLed> Leds
|
||||
{
|
||||
get => _leds;
|
||||
set => SetAndNotify(ref _leds, value);
|
||||
private set => SetAndNotify(ref _leds, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the X-position of the device
|
||||
/// </summary>
|
||||
public double X
|
||||
{
|
||||
get => DeviceEntity.X;
|
||||
@ -71,6 +97,9 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Y-position of the device
|
||||
/// </summary>
|
||||
public double Y
|
||||
{
|
||||
get => DeviceEntity.Y;
|
||||
@ -81,6 +110,9 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the rotation of the device
|
||||
/// </summary>
|
||||
public double Rotation
|
||||
{
|
||||
get => DeviceEntity.Rotation;
|
||||
@ -91,6 +123,9 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the scale of the device
|
||||
/// </summary>
|
||||
public double Scale
|
||||
{
|
||||
get => DeviceEntity.Scale;
|
||||
@ -101,6 +136,9 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Z-index of the device
|
||||
/// </summary>
|
||||
public int ZIndex
|
||||
{
|
||||
get => DeviceEntity.ZIndex;
|
||||
@ -111,13 +149,22 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
internal DeviceEntity DeviceEntity { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{RgbDevice.DeviceInfo.DeviceType}] {RgbDevice.DeviceInfo.DeviceName} - {X}.{Y}.{ZIndex}";
|
||||
}
|
||||
|
||||
public event EventHandler DeviceUpdated;
|
||||
/// <summary>
|
||||
/// Occurs when the underlying RGB.NET device was updated
|
||||
/// </summary>
|
||||
public event EventHandler? DeviceUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DeviceUpdated" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDeviceUpdated()
|
||||
{
|
||||
DeviceUpdated?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
@ -3,35 +3,51 @@ using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an RGB LED contained in an <see cref="ArtemisDevice" />
|
||||
/// </summary>
|
||||
public class ArtemisLed : CorePropertyChanged
|
||||
{
|
||||
private SKRect _absoluteRenderRectangle;
|
||||
private SKRect _renderRectangle;
|
||||
|
||||
public ArtemisLed(Led led, ArtemisDevice device)
|
||||
internal ArtemisLed(Led led, ArtemisDevice device)
|
||||
{
|
||||
RgbLed = led;
|
||||
Device = device;
|
||||
CalculateRenderRectangle();
|
||||
}
|
||||
|
||||
public int LedIndex => Device.Leds.IndexOf(this);
|
||||
/// <summary>
|
||||
/// Gets the RGB.NET LED backing this Artemis LED
|
||||
/// </summary>
|
||||
public Led RgbLed { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device that contains this LED
|
||||
/// </summary>
|
||||
public ArtemisDevice Device { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rectangle covering the LED, sized to match the render scale and positioned relative to the
|
||||
/// <see cref="Device" />
|
||||
/// </summary>
|
||||
public SKRect RenderRectangle
|
||||
{
|
||||
get => _renderRectangle;
|
||||
private set => SetAndNotify(ref _renderRectangle, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rectangle covering the LED, sized to match the render scale
|
||||
/// </summary>
|
||||
public SKRect AbsoluteRenderRectangle
|
||||
{
|
||||
get => _absoluteRenderRectangle;
|
||||
private set => SetAndNotify(ref _absoluteRenderRectangle, value);
|
||||
}
|
||||
|
||||
public void CalculateRenderRectangle()
|
||||
internal void CalculateRenderRectangle()
|
||||
{
|
||||
RenderRectangle = SKRect.Create(
|
||||
(RgbLed.LedRectangle.Location.X * Device.Surface.Scale).RoundToInt(),
|
||||
|
||||
@ -6,6 +6,9 @@ using RGB.NET.Core;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a surface of a specific scale, containing all the available <see cref="ArtemisDevice" />s
|
||||
/// </summary>
|
||||
public class ArtemisSurface : CorePropertyChanged
|
||||
{
|
||||
private List<ArtemisDevice> _devices;
|
||||
@ -17,14 +20,14 @@ namespace Artemis.Core
|
||||
{
|
||||
SurfaceEntity = new SurfaceEntity {DeviceEntities = new List<DeviceEntity>()};
|
||||
EntityId = Guid.NewGuid();
|
||||
|
||||
Name = name;
|
||||
Scale = scale;
|
||||
RgbSurface = rgbSurface;
|
||||
IsActive = false;
|
||||
|
||||
_name = name;
|
||||
_scale = scale;
|
||||
_isActive = false;
|
||||
|
||||
// Devices are not populated here but as they are detected
|
||||
Devices = new List<ArtemisDevice>();
|
||||
_devices = new List<ArtemisDevice>();
|
||||
|
||||
ApplyToEntity();
|
||||
}
|
||||
@ -33,36 +36,51 @@ namespace Artemis.Core
|
||||
{
|
||||
SurfaceEntity = surfaceEntity;
|
||||
EntityId = surfaceEntity.Id;
|
||||
|
||||
RgbSurface = rgbSurface;
|
||||
Scale = scale;
|
||||
Name = surfaceEntity.Name;
|
||||
IsActive = surfaceEntity.IsActive;
|
||||
|
||||
_scale = scale;
|
||||
_name = surfaceEntity.Name;
|
||||
_isActive = surfaceEntity.IsActive;
|
||||
|
||||
// Devices are not populated here but as they are detected
|
||||
Devices = new List<ArtemisDevice>();
|
||||
_devices = new List<ArtemisDevice>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RGB.NET surface backing this Artemis surface
|
||||
/// </summary>
|
||||
public RGBSurface RgbSurface { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scale at which this surface is rendered
|
||||
/// </summary>
|
||||
public double Scale
|
||||
{
|
||||
get => _scale;
|
||||
private set => SetAndNotify(ref _scale, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the surface
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set => SetAndNotify(ref _name, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether this surface is the currently active surface
|
||||
/// </summary>
|
||||
public bool IsActive
|
||||
{
|
||||
get => _isActive;
|
||||
internal set => SetAndNotify(ref _isActive, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of devices this surface contains
|
||||
/// </summary>
|
||||
public List<ArtemisDevice> Devices
|
||||
{
|
||||
get => _devices;
|
||||
@ -72,6 +90,10 @@ namespace Artemis.Core
|
||||
internal SurfaceEntity SurfaceEntity { get; set; }
|
||||
internal Guid EntityId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates the scale of the surface
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void UpdateScale(double value)
|
||||
{
|
||||
Scale = value;
|
||||
@ -89,16 +111,20 @@ namespace Artemis.Core
|
||||
|
||||
// Add missing device entities, don't remove old ones in case they come back later
|
||||
foreach (DeviceEntity deviceEntity in Devices.Select(d => d.DeviceEntity).ToList())
|
||||
{
|
||||
if (!SurfaceEntity.DeviceEntities.Contains(deviceEntity))
|
||||
SurfaceEntity.DeviceEntities.Add(deviceEntity);
|
||||
}
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler<EventArgs> ScaleChanged;
|
||||
/// <summary>
|
||||
/// Occurs when the scale of the surface is changed
|
||||
/// </summary>
|
||||
public event EventHandler<EventArgs>? ScaleChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="ScaleChanged" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnScaleChanged()
|
||||
{
|
||||
ScaleChanged?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
@ -9,6 +8,9 @@ using Humanizer;
|
||||
|
||||
namespace Artemis.Core.DataModelExpansions
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a data model that contains information on a game/application etc.
|
||||
/// </summary>
|
||||
public abstract class DataModel
|
||||
{
|
||||
private readonly Dictionary<string, DataModel> _dynamicDataModels = new Dictionary<string, DataModel>();
|
||||
@ -154,11 +156,17 @@ namespace Artemis.Core.DataModelExpansions
|
||||
/// </summary>
|
||||
public event EventHandler<DynamicDataModelEventArgs>? DynamicDataModelRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DynamicDataModelAdded" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDynamicDataModelAdded(DynamicDataModelEventArgs e)
|
||||
{
|
||||
DynamicDataModelAdded?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DynamicDataModelRemoved" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDynamicDataModelRemoved(DynamicDataModelEventArgs e)
|
||||
{
|
||||
DynamicDataModelRemoved?.Invoke(this, e);
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a configuration dialog for a <see cref="Plugin" />
|
||||
/// </summary>
|
||||
public interface IPluginConfigurationDialog
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -9,8 +9,8 @@ namespace Artemis.Core.LayerBrushes
|
||||
public abstract class BaseLayerBrush : CorePropertyChanged, IDisposable
|
||||
{
|
||||
private LayerBrushType _brushType;
|
||||
private ILayerBrushConfigurationDialog _configurationDialog;
|
||||
private LayerBrushDescriptor _descriptor;
|
||||
private ILayerBrushConfigurationDialog? _configurationDialog;
|
||||
private LayerBrushDescriptor? _descriptor;
|
||||
private Layer _layer;
|
||||
private bool _supportsTransformation = true;
|
||||
|
||||
@ -26,7 +26,7 @@ namespace Artemis.Core.LayerBrushes
|
||||
/// <summary>
|
||||
/// Gets the descriptor of this brush
|
||||
/// </summary>
|
||||
public LayerBrushDescriptor Descriptor
|
||||
public LayerBrushDescriptor? Descriptor
|
||||
{
|
||||
get => _descriptor;
|
||||
internal set => SetAndNotify(ref _descriptor, value);
|
||||
@ -35,7 +35,7 @@ namespace Artemis.Core.LayerBrushes
|
||||
/// <summary>
|
||||
/// Gets or sets a configuration dialog complementing the regular properties
|
||||
/// </summary>
|
||||
public ILayerBrushConfigurationDialog ConfigurationDialog
|
||||
public ILayerBrushConfigurationDialog? ConfigurationDialog
|
||||
{
|
||||
get => _configurationDialog;
|
||||
protected set => SetAndNotify(ref _configurationDialog, value);
|
||||
@ -53,12 +53,12 @@ namespace Artemis.Core.LayerBrushes
|
||||
/// <summary>
|
||||
/// Gets the ID of the <see cref="LayerBrushProvider" /> that provided this effect
|
||||
/// </summary>
|
||||
public string ProviderId => Descriptor?.Provider?.Id;
|
||||
public string? ProviderId => Descriptor?.Provider.Id;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the layer property group without knowing it's type
|
||||
/// </summary>
|
||||
public virtual LayerPropertyGroup BaseProperties => null;
|
||||
public virtual LayerPropertyGroup? BaseProperties => null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the brush supports transformations
|
||||
@ -70,7 +70,7 @@ namespace Artemis.Core.LayerBrushes
|
||||
protected set
|
||||
{
|
||||
if (value && BrushType == LayerBrushType.RgbNet)
|
||||
throw new ArtemisPluginFeatureException(Descriptor.Provider, "An RGB.NET brush cannot support transformation");
|
||||
throw new ArtemisPluginFeatureException(Descriptor?.Provider!, "An RGB.NET brush cannot support transformation");
|
||||
_supportsTransformation = value;
|
||||
}
|
||||
}
|
||||
@ -105,7 +105,7 @@ namespace Artemis.Core.LayerBrushes
|
||||
public void Dispose()
|
||||
{
|
||||
DisableLayerBrush();
|
||||
BaseProperties.Dispose();
|
||||
BaseProperties?.Dispose();
|
||||
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
@ -46,7 +46,7 @@ namespace Artemis.Core.LayerBrushes
|
||||
/// <summary>
|
||||
/// Determines whether the provided <paramref name="reference" /> references to a brush provided by this descriptor
|
||||
/// </summary>
|
||||
public bool MatchesLayerBrushReference(LayerBrushReference reference)
|
||||
public bool MatchesLayerBrushReference(LayerBrushReference? reference)
|
||||
{
|
||||
if (reference == null)
|
||||
return false;
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
namespace Artemis.Core.LayerEffects
|
||||
{
|
||||
public interface IEffectConfigurationViewModel
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
namespace Artemis.Core.LayerEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a configuration dialog for a <see cref="LayerEffect{T}" />
|
||||
/// </summary>
|
||||
public interface ILayerEffectConfigurationDialog
|
||||
{
|
||||
}
|
||||
|
||||
@ -160,6 +160,7 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (PluginFeature feature in Features)
|
||||
|
||||
@ -104,7 +104,7 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
private void TimerOnElapsed(object sender, ElapsedEventArgs e)
|
||||
private void TimerOnElapsed(object? sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (!Feature.IsEnabled)
|
||||
return;
|
||||
@ -128,12 +128,12 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
private void FeatureOnEnabled(object sender, EventArgs e)
|
||||
private void FeatureOnEnabled(object? sender, EventArgs e)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
|
||||
private void FeatureOnDisabled(object sender, EventArgs e)
|
||||
private void FeatureOnDisabled(object? sender, EventArgs e)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
@ -198,7 +198,7 @@ namespace Artemis.Core.Services
|
||||
module.InternalRender(args.DeltaTime, _surfaceService.ActiveSurface, canvas, _rgbService.BitmapBrush.Bitmap.Info);
|
||||
}
|
||||
|
||||
OnFrameRendering(new FrameRenderingEventArgs(modules, canvas, args.DeltaTime, _rgbService.Surface));
|
||||
OnFrameRendering(new FrameRenderingEventArgs(canvas, args.DeltaTime, _rgbService.Surface));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@ -44,6 +44,10 @@ namespace Artemis.Core.Services
|
||||
/// </summary>
|
||||
/// <param name="plugin">The plugin to enable</param>
|
||||
/// <param name="saveState">Whether or not to save the new enabled state</param>
|
||||
/// <param name="ignorePluginLock">
|
||||
/// Whether or not plugin lock files should be ignored. If set to <see langword="true" />,
|
||||
/// plugins with lock files will load successfully
|
||||
/// </param>
|
||||
void EnablePlugin(Plugin plugin, bool saveState, bool ignorePluginLock = false);
|
||||
|
||||
/// <summary>
|
||||
@ -95,7 +99,7 @@ namespace Artemis.Core.Services
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <returns></returns>
|
||||
Plugin GetPluginByAssembly(Assembly assembly);
|
||||
Plugin? GetPluginByAssembly(Assembly? assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the plugin info of the current call stack
|
||||
|
||||
@ -138,8 +138,10 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public Plugin? GetPluginByAssembly(Assembly assembly)
|
||||
public Plugin? GetPluginByAssembly(Assembly? assembly)
|
||||
{
|
||||
if (assembly == null)
|
||||
return null;
|
||||
lock (_plugins)
|
||||
{
|
||||
return _plugins.FirstOrDefault(p => p.Assembly == assembly);
|
||||
@ -159,8 +161,8 @@ namespace Artemis.Core.Services
|
||||
|
||||
foreach (StackFrame stackFrame in stackFrames)
|
||||
{
|
||||
Assembly assembly = stackFrame.GetMethod().DeclaringType.Assembly;
|
||||
Plugin plugin = GetPluginByAssembly(assembly);
|
||||
Assembly? assembly = stackFrame.GetMethod()?.DeclaringType?.Assembly;
|
||||
Plugin? plugin = GetPluginByAssembly(assembly);
|
||||
if (plugin != null)
|
||||
return plugin;
|
||||
}
|
||||
@ -179,7 +181,7 @@ namespace Artemis.Core.Services
|
||||
{
|
||||
if (LoadingPlugins)
|
||||
throw new ArtemisCoreException("Cannot load plugins while a previous load hasn't been completed yet.");
|
||||
|
||||
|
||||
LoadingPlugins = true;
|
||||
|
||||
// Unload all currently loaded plugins first
|
||||
@ -207,8 +209,10 @@ namespace Artemis.Core.Services
|
||||
public void UnloadPlugins()
|
||||
{
|
||||
// Unload all plugins
|
||||
// ReSharper disable InconsistentlySynchronizedField - UnloadPlugin will lock it when it has to
|
||||
while (_plugins.Count > 0)
|
||||
UnloadPlugin(_plugins[0]);
|
||||
// ReSharper restore InconsistentlySynchronizedField
|
||||
|
||||
lock (_plugins)
|
||||
{
|
||||
@ -297,7 +301,11 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
catch (ReflectionTypeLoadException e)
|
||||
{
|
||||
throw new ArtemisPluginException(plugin, "Failed to initialize the plugin assembly", new AggregateException(e.LoaderExceptions));
|
||||
throw new ArtemisPluginException(
|
||||
plugin,
|
||||
"Failed to initialize the plugin assembly",
|
||||
new AggregateException(e.LoaderExceptions.Where(le => le != null).Cast<Exception>().ToArray())
|
||||
);
|
||||
}
|
||||
|
||||
if (!featureTypes.Any())
|
||||
@ -318,7 +326,7 @@ namespace Artemis.Core.Services
|
||||
|
||||
// Load the enabled state and if not found, default to true
|
||||
instance.Entity = plugin.Entity.Features.FirstOrDefault(i => i.Type == featureType.FullName) ??
|
||||
new PluginFeatureEntity {IsEnabled = true, Type = featureType.FullName};
|
||||
new PluginFeatureEntity {IsEnabled = true, Type = featureType.FullName!};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -385,7 +393,7 @@ namespace Artemis.Core.Services
|
||||
|
||||
plugin.SetEnabled(false);
|
||||
|
||||
plugin.Kernel.Dispose();
|
||||
plugin.Kernel?.Dispose();
|
||||
plugin.Kernel = null;
|
||||
|
||||
GC.Collect();
|
||||
@ -487,28 +495,22 @@ namespace Artemis.Core.Services
|
||||
_pluginRepository.SavePlugin(plugin.Entity);
|
||||
}
|
||||
|
||||
private PluginFeatureEntity GetOrCreateFeatureEntity(PluginFeature feature)
|
||||
{
|
||||
return feature.Plugin.Entity.Features.FirstOrDefault(i => i.Type == feature.GetType().FullName) ??
|
||||
new PluginFeatureEntity {IsEnabled = true, Type = feature.GetType().FullName};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler CopyingBuildInPlugins;
|
||||
public event EventHandler<PluginEventArgs> PluginLoading;
|
||||
public event EventHandler<PluginEventArgs> PluginLoaded;
|
||||
public event EventHandler<PluginEventArgs> PluginUnloaded;
|
||||
public event EventHandler<PluginEventArgs> PluginEnabling;
|
||||
public event EventHandler<PluginEventArgs> PluginEnabled;
|
||||
public event EventHandler<PluginEventArgs> PluginDisabled;
|
||||
public event EventHandler? CopyingBuildInPlugins;
|
||||
public event EventHandler<PluginEventArgs>? PluginLoading;
|
||||
public event EventHandler<PluginEventArgs>? PluginLoaded;
|
||||
public event EventHandler<PluginEventArgs>? PluginUnloaded;
|
||||
public event EventHandler<PluginEventArgs>? PluginEnabling;
|
||||
public event EventHandler<PluginEventArgs>? PluginEnabled;
|
||||
public event EventHandler<PluginEventArgs>? PluginDisabled;
|
||||
|
||||
public event EventHandler<PluginFeatureEventArgs> PluginFeatureEnabling;
|
||||
public event EventHandler<PluginFeatureEventArgs> PluginFeatureEnabled;
|
||||
public event EventHandler<PluginFeatureEventArgs> PluginFeatureDisabled;
|
||||
public event EventHandler<PluginFeatureEventArgs> PluginFeatureEnableFailed;
|
||||
public event EventHandler<PluginFeatureEventArgs>? PluginFeatureEnabling;
|
||||
public event EventHandler<PluginFeatureEventArgs>? PluginFeatureEnabled;
|
||||
public event EventHandler<PluginFeatureEventArgs>? PluginFeatureDisabled;
|
||||
public event EventHandler<PluginFeatureEventArgs>? PluginFeatureEnableFailed;
|
||||
|
||||
protected virtual void OnCopyingBuildInPlugins()
|
||||
{
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core.DeviceProviders;
|
||||
using Artemis.Storage.Entities.Surface;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using RGB.NET.Core;
|
||||
@ -44,8 +45,8 @@ namespace Artemis.Core.Services
|
||||
// Add all current devices
|
||||
foreach (IRGBDevice rgbDevice in _rgbService.LoadedDevices)
|
||||
{
|
||||
PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice);
|
||||
configuration.Devices.Add(new ArtemisDevice(rgbDevice, pluginFeature, configuration));
|
||||
DeviceProvider deviceProvider = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice);
|
||||
configuration.Devices.Add(new ArtemisDevice(rgbDevice, deviceProvider, configuration));
|
||||
}
|
||||
|
||||
lock (_surfaceConfigurations)
|
||||
@ -136,8 +137,8 @@ namespace Artemis.Core.Services
|
||||
IRGBDevice device = _rgbService.Surface.Devices.FirstOrDefault(d => d.GetDeviceIdentifier() == position.DeviceIdentifier);
|
||||
if (device != null)
|
||||
{
|
||||
PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(device);
|
||||
surfaceConfiguration.Devices.Add(new ArtemisDevice(device, pluginFeature, surfaceConfiguration, position));
|
||||
DeviceProvider deviceProvider = _pluginManagementService.GetDeviceProviderByDevice(device);
|
||||
surfaceConfiguration.Devices.Add(new ArtemisDevice(device, deviceProvider, surfaceConfiguration, position));
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,8 +179,8 @@ namespace Artemis.Core.Services
|
||||
DeviceEntity existingDeviceConfig = surface.SurfaceEntity.DeviceEntities.FirstOrDefault(d => d.DeviceIdentifier == deviceIdentifier);
|
||||
if (existingDeviceConfig != null)
|
||||
{
|
||||
PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice);
|
||||
device = new ArtemisDevice(rgbDevice, pluginFeature, surface, existingDeviceConfig);
|
||||
DeviceProvider deviceProvider = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice);
|
||||
device = new ArtemisDevice(rgbDevice, deviceProvider, surface, existingDeviceConfig);
|
||||
}
|
||||
// Fall back on creating a new device
|
||||
else
|
||||
@ -189,8 +190,8 @@ namespace Artemis.Core.Services
|
||||
rgbDevice.DeviceInfo,
|
||||
deviceIdentifier
|
||||
);
|
||||
PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice);
|
||||
device = new ArtemisDevice(rgbDevice, pluginFeature, surface);
|
||||
DeviceProvider deviceProvider = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice);
|
||||
device = new ArtemisDevice(rgbDevice, deviceProvider, surface);
|
||||
}
|
||||
|
||||
surface.Devices.Add(device);
|
||||
|
||||
@ -38,7 +38,7 @@ namespace Artemis.Core
|
||||
OnConditionOperatorRemoved(new ConditionOperatorStoreEvent(registration));
|
||||
}
|
||||
|
||||
public static ConditionOperatorRegistration Get(Guid pluginGuid, string type)
|
||||
public static ConditionOperatorRegistration? Get(Guid pluginGuid, string type)
|
||||
{
|
||||
lock (Registrations)
|
||||
{
|
||||
|
||||
@ -10,6 +10,9 @@ namespace Artemis.Core
|
||||
|
||||
public static DataBindingModifierTypeRegistration Add(BaseDataBindingModifierType modifierType)
|
||||
{
|
||||
if (modifierType.Plugin == null)
|
||||
throw new ArtemisCoreException("Cannot add a data binding modifier type that is not associated with a plugin");
|
||||
|
||||
DataBindingModifierTypeRegistration typeRegistration;
|
||||
lock (Registrations)
|
||||
{
|
||||
@ -38,7 +41,7 @@ namespace Artemis.Core
|
||||
OnDataBindingModifierRemoved(new DataBindingModifierTypeStoreEvent(typeRegistration));
|
||||
}
|
||||
|
||||
public static DataBindingModifierTypeRegistration Get(Guid pluginGuid, string type)
|
||||
public static DataBindingModifierTypeRegistration? Get(Guid pluginGuid, string type)
|
||||
{
|
||||
lock (Registrations)
|
||||
{
|
||||
@ -74,8 +77,8 @@ namespace Artemis.Core
|
||||
|
||||
#region Events
|
||||
|
||||
public static event EventHandler<DataBindingModifierTypeStoreEvent> DataBindingModifierAdded;
|
||||
public static event EventHandler<DataBindingModifierTypeStoreEvent> DataBindingModifierRemoved;
|
||||
public static event EventHandler<DataBindingModifierTypeStoreEvent>? DataBindingModifierAdded;
|
||||
public static event EventHandler<DataBindingModifierTypeStoreEvent>? DataBindingModifierRemoved;
|
||||
|
||||
private static void OnDataBindingModifierAdded(DataBindingModifierTypeStoreEvent e)
|
||||
{
|
||||
|
||||
@ -47,7 +47,7 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static DataModelRegistration Get(string id)
|
||||
public static DataModelRegistration? Get(string id)
|
||||
{
|
||||
lock (Registrations)
|
||||
{
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
@ -42,7 +41,7 @@ namespace Artemis.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the provided URL in the default web browser
|
||||
/// Opens the provided URL in the default web browser
|
||||
/// </summary>
|
||||
/// <param name="url">The URL to open</param>
|
||||
/// <returns>The process created to open the URL</returns>
|
||||
@ -67,7 +66,10 @@ namespace Artemis.Core
|
||||
|
||||
#region Events
|
||||
|
||||
public static event EventHandler ShutdownRequested;
|
||||
/// <summary>
|
||||
/// Occurs when the core has requested an application shutdown
|
||||
/// </summary>
|
||||
public static event EventHandler? ShutdownRequested;
|
||||
|
||||
private static void OnShutdownRequested()
|
||||
{
|
||||
@ -75,7 +77,5 @@ namespace Artemis.Core
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -28,6 +28,7 @@
|
||||
<NrtRequiredVcs>git</NrtRequiredVcs>
|
||||
<NrtShowRevision>true</NrtShowRevision>
|
||||
<Version>2.0.0</Version>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DocumentationFile>bin\x64\Release\Artemis.UI.Shared.xml</DocumentationFile>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user