mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Core - Nullable refactoring
Core - Nullable refactoring Core - Nullable refactoring (finish)
This commit is contained in:
parent
b185b28645
commit
fb3466e102
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Artemis.Storage.Entities.Plugins;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
@ -34,13 +35,13 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public static readonly PluginInfo CorePluginInfo = new PluginInfo
|
||||
{
|
||||
Guid = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"), Name = "Artemis Core"
|
||||
Guid = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"), Name = "Artemis Core", Version = new Version(2,0)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The plugin used by core components of Artemis
|
||||
/// </summary>
|
||||
public static readonly Plugin CorePlugin = new Plugin(CorePluginInfo, new DirectoryInfo(ApplicationFolder));
|
||||
public static readonly Plugin CorePlugin = new Plugin(CorePluginInfo, new DirectoryInfo(ApplicationFolder), null);
|
||||
|
||||
internal static readonly CorePluginFeature CorePluginFeature = new CorePluginFeature {Plugin = CorePlugin};
|
||||
internal static readonly EffectPlaceholderPlugin EffectPlaceholderPlugin = new EffectPlaceholderPlugin {Plugin = CorePlugin};
|
||||
|
||||
@ -8,6 +8,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// A static class providing <see cref="Process" /> extensions
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1060:Move pinvokes to native methods class", Justification = "I don't care, piss off")]
|
||||
public static class ProcessExtensions
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@ -20,7 +20,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
/// <param name="parent">The parent of the folder</param>
|
||||
/// <param name="name">The name of the folder</param>
|
||||
public Folder(ProfileElement parent, string name)
|
||||
public Folder(ProfileElement parent, string name) : base(parent.Profile)
|
||||
{
|
||||
FolderEntity = new FolderEntity();
|
||||
EntityId = Guid.NewGuid();
|
||||
@ -30,13 +30,10 @@ namespace Artemis.Core
|
||||
Name = name;
|
||||
Enabled = true;
|
||||
|
||||
LayerEffectsList = new List<BaseLayerEffect>();
|
||||
ExpandedPropertyGroups = new List<string>();
|
||||
|
||||
Parent.AddChild(this);
|
||||
}
|
||||
|
||||
internal Folder(Profile profile, ProfileElement parent, FolderEntity folderEntity)
|
||||
internal Folder(Profile profile, ProfileElement parent, FolderEntity folderEntity) : base(parent.Profile)
|
||||
{
|
||||
FolderEntity = folderEntity;
|
||||
EntityId = folderEntity.Id;
|
||||
@ -47,9 +44,6 @@ namespace Artemis.Core
|
||||
Enabled = folderEntity.Enabled;
|
||||
Order = folderEntity.Order;
|
||||
|
||||
LayerEffectsList = new List<BaseLayerEffect>();
|
||||
ExpandedPropertyGroups = new List<string>();
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
/// <param name="parent">The parent of the layer</param>
|
||||
/// <param name="name">The name of the layer</param>
|
||||
public Layer(ProfileElement parent, string name)
|
||||
public Layer(ProfileElement parent, string name) : base(parent.Profile)
|
||||
{
|
||||
LayerEntity = new LayerEntity();
|
||||
EntityId = Guid.NewGuid();
|
||||
@ -40,15 +40,13 @@ namespace Artemis.Core
|
||||
_general = new LayerGeneralProperties();
|
||||
_transform = new LayerTransformProperties();
|
||||
|
||||
LayerEffectsList = new List<BaseLayerEffect>();
|
||||
_leds = new List<ArtemisLed>();
|
||||
ExpandedPropertyGroups = new List<string>();
|
||||
|
||||
Initialize();
|
||||
Parent.AddChild(this);
|
||||
}
|
||||
|
||||
internal Layer(Profile profile, ProfileElement parent, LayerEntity layerEntity)
|
||||
internal Layer(Profile profile, ProfileElement parent, LayerEntity layerEntity) : base(parent.Profile)
|
||||
{
|
||||
LayerEntity = layerEntity;
|
||||
EntityId = layerEntity.Id;
|
||||
@ -58,9 +56,7 @@ namespace Artemis.Core
|
||||
_general = new LayerGeneralProperties();
|
||||
_transform = new LayerTransformProperties();
|
||||
|
||||
LayerEffectsList = new List<BaseLayerEffect>();
|
||||
_leds = new List<ArtemisLed>();
|
||||
ExpandedPropertyGroups = new List<string>();
|
||||
|
||||
Load();
|
||||
Initialize();
|
||||
@ -263,17 +259,12 @@ namespace Artemis.Core
|
||||
|
||||
private void ApplyShapeType()
|
||||
{
|
||||
switch (General.ShapeType.CurrentValue)
|
||||
LayerShape = General.ShapeType.CurrentValue switch
|
||||
{
|
||||
case LayerShapeType.Ellipse:
|
||||
LayerShape = new EllipseShape(this);
|
||||
break;
|
||||
case LayerShapeType.Rectangle:
|
||||
LayerShape = new RectangleShape(this);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
LayerShapeType.Ellipse => new EllipseShape(this),
|
||||
LayerShapeType.Rectangle => new RectangleShape(this),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -25,7 +25,13 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
protected LayerProperty()
|
||||
{
|
||||
// Cant define generic types as nullable ¯\_(ツ)_/¯
|
||||
// These are set right after construction to keep the constructor (and inherited constructs) clean
|
||||
ProfileElement = null!;
|
||||
LayerPropertyGroup = null!;
|
||||
Path = null!;
|
||||
Entity = null!;
|
||||
PropertyDescription = null!;
|
||||
|
||||
CurrentValue = default!;
|
||||
DefaultValue = default!;
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using Artemis.Core.LayerBrushes;
|
||||
using Artemis.Core.LayerEffects;
|
||||
using Artemis.Core.Properties;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Humanizer;
|
||||
|
||||
@ -30,6 +29,12 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
protected LayerPropertyGroup()
|
||||
{
|
||||
// These are set right after construction to keep the constructor (and inherited constructs) clean
|
||||
GroupDescription = null!;
|
||||
Feature = null!;
|
||||
ProfileElement = null!;
|
||||
Path = null!;
|
||||
|
||||
_layerProperties = new List<ILayerProperty>();
|
||||
_layerPropertyGroups = new List<LayerPropertyGroup>();
|
||||
}
|
||||
@ -52,7 +57,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// The parent group of this group
|
||||
/// </summary>
|
||||
public LayerPropertyGroup Parent { get; internal set; }
|
||||
public LayerPropertyGroup? Parent { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path of this property group
|
||||
@ -67,12 +72,12 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// The layer brush this property group belongs to
|
||||
/// </summary>
|
||||
public BaseLayerBrush LayerBrush { get; internal set; }
|
||||
public BaseLayerBrush? LayerBrush { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The layer effect this property group belongs to
|
||||
/// </summary>
|
||||
public BaseLayerEffect LayerEffect { get; internal set; }
|
||||
public BaseLayerEffect? LayerEffect { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the property is hidden in the UI
|
||||
@ -139,19 +144,16 @@ namespace Artemis.Core
|
||||
PropertyGroupInitialized?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
internal void Initialize(RenderProfileElement profileElement, [NotNull] string path, PluginFeature feature)
|
||||
internal void Initialize(RenderProfileElement profileElement, string path, PluginFeature feature)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
if (feature == null)
|
||||
throw new ArgumentNullException(nameof(feature));
|
||||
if (path == null) throw new ArgumentNullException(nameof(path));
|
||||
|
||||
// Doubt this will happen but let's make sure
|
||||
if (PropertiesInitialized)
|
||||
throw new ArtemisCoreException("Layer property group already initialized, wut");
|
||||
|
||||
Feature = feature;
|
||||
ProfileElement = profileElement;
|
||||
Feature = feature ?? throw new ArgumentNullException(nameof(feature));
|
||||
ProfileElement = profileElement ?? throw new ArgumentNullException(nameof(profileElement));
|
||||
Path = path.TrimEnd('.');
|
||||
|
||||
// Get all properties with a PropertyDescriptionAttribute
|
||||
@ -209,8 +211,7 @@ namespace Artemis.Core
|
||||
if (!typeof(ILayerProperty).IsAssignableFrom(propertyInfo.PropertyType))
|
||||
throw new ArtemisPluginException($"Layer property with PropertyDescription attribute must be of type LayerProperty at {path}");
|
||||
|
||||
ILayerProperty instance = (ILayerProperty) Activator.CreateInstance(propertyInfo.PropertyType, true);
|
||||
if (instance == null)
|
||||
if (!(Activator.CreateInstance(propertyInfo.PropertyType, true) is ILayerProperty instance))
|
||||
throw new ArtemisPluginException($"Failed to create instance of layer property at {path}");
|
||||
|
||||
// Ensure the description has a name, if not this is a good point to set it based on the property info
|
||||
@ -230,8 +231,7 @@ namespace Artemis.Core
|
||||
if (!typeof(LayerPropertyGroup).IsAssignableFrom(propertyInfo.PropertyType))
|
||||
throw new ArtemisPluginException("Layer property with PropertyGroupDescription attribute must be of type LayerPropertyGroup");
|
||||
|
||||
LayerPropertyGroup instance = (LayerPropertyGroup) Activator.CreateInstance(propertyInfo.PropertyType);
|
||||
if (instance == null)
|
||||
if (!(Activator.CreateInstance(propertyInfo.PropertyType) is LayerPropertyGroup instance))
|
||||
throw new ArtemisPluginException($"Failed to create instance of layer property group at {path + propertyInfo.Name}");
|
||||
|
||||
// Ensure the description has a name, if not this is a good point to set it based on the property info
|
||||
@ -250,7 +250,7 @@ namespace Artemis.Core
|
||||
|
||||
private PropertyEntity GetPropertyEntity(RenderProfileElement profileElement, string path, out bool fromStorage)
|
||||
{
|
||||
PropertyEntity entity = profileElement.RenderElementEntity.PropertyEntities.FirstOrDefault(p => p.FeatureId == Feature.Id && p.Path == path);
|
||||
PropertyEntity? entity = profileElement.RenderElementEntity.PropertyEntities.FirstOrDefault(p => p.FeatureId == Feature.Id && p.Path == path);
|
||||
fromStorage = entity != null;
|
||||
if (entity == null)
|
||||
{
|
||||
@ -298,18 +298,18 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Occurs when the property group has initialized all its children
|
||||
/// </summary>
|
||||
public event EventHandler PropertyGroupInitialized;
|
||||
public event EventHandler? PropertyGroupInitialized;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when one of the current value of one of the layer properties in this group changes by some form of input
|
||||
/// <para>Note: Will not trigger on properties in child groups</para>
|
||||
/// </summary>
|
||||
public event EventHandler<LayerPropertyEventArgs> LayerPropertyOnCurrentValueSet;
|
||||
public event EventHandler<LayerPropertyEventArgs>? LayerPropertyOnCurrentValueSet;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the <see cref="IsHidden" /> value of the layer property was updated
|
||||
/// </summary>
|
||||
public event EventHandler VisibilityChanged;
|
||||
public event EventHandler? VisibilityChanged;
|
||||
|
||||
internal virtual void OnVisibilityChanged()
|
||||
{
|
||||
|
||||
@ -20,7 +20,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets a the path outlining the shape
|
||||
/// </summary>
|
||||
public SKPath Path { get; protected set; }
|
||||
public SKPath? Path { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the <see cref="Path" />
|
||||
|
||||
@ -15,7 +15,7 @@ namespace Artemis.Core
|
||||
private bool _isActivated;
|
||||
private readonly object _lock = new object();
|
||||
|
||||
internal Profile(ProfileModule module, string name)
|
||||
internal Profile(ProfileModule module, string name) : base(null!)
|
||||
{
|
||||
ProfileEntity = new ProfileEntity();
|
||||
EntityId = Guid.NewGuid();
|
||||
@ -30,7 +30,7 @@ namespace Artemis.Core
|
||||
Save();
|
||||
}
|
||||
|
||||
internal Profile(ProfileModule module, ProfileEntity profileEntity)
|
||||
internal Profile(ProfileModule module, ProfileEntity profileEntity) : base(null!)
|
||||
{
|
||||
Profile = this;
|
||||
ProfileEntity = profileEntity;
|
||||
@ -149,7 +149,7 @@ namespace Artemis.Core
|
||||
ChildrenList.Clear();
|
||||
|
||||
// Populate the profile starting at the root, the rest is populated recursively
|
||||
FolderEntity rootFolder = ProfileEntity.Folders.FirstOrDefault(f => f.ParentId == EntityId);
|
||||
FolderEntity? rootFolder = ProfileEntity.Folders.FirstOrDefault(f => f.ParentId == EntityId);
|
||||
if (rootFolder == null)
|
||||
{
|
||||
Folder _ = new Folder(this, "Root folder");
|
||||
|
||||
@ -13,7 +13,7 @@ namespace Artemis.Core
|
||||
{
|
||||
private bool _enabled;
|
||||
private Guid _entityId;
|
||||
private string _name;
|
||||
private string? _name;
|
||||
private int _order;
|
||||
private ProfileElement? _parent;
|
||||
private Profile _profile;
|
||||
@ -21,8 +21,9 @@ namespace Artemis.Core
|
||||
internal List<ProfileElement> ChildrenList;
|
||||
internal bool Disposed;
|
||||
|
||||
internal ProfileElement()
|
||||
internal ProfileElement(Profile profile)
|
||||
{
|
||||
_profile = profile;
|
||||
ChildrenList = new List<ProfileElement>();
|
||||
}
|
||||
|
||||
@ -56,7 +57,16 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// The element's children
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<ProfileElement> Children => ChildrenList.AsReadOnly();
|
||||
public ReadOnlyCollection<ProfileElement> Children
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (ChildrenList)
|
||||
{
|
||||
return ChildrenList.AsReadOnly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The order in which this element appears in the update loop and editor
|
||||
@ -70,7 +80,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// The name which appears in the editor
|
||||
/// </summary>
|
||||
public string Name
|
||||
public string? Name
|
||||
{
|
||||
get => _name;
|
||||
set => SetAndNotify(ref _name, value);
|
||||
|
||||
@ -16,10 +16,12 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public abstract class RenderProfileElement : ProfileElement
|
||||
{
|
||||
internal RenderProfileElement()
|
||||
internal RenderProfileElement(Profile profile) : base(profile)
|
||||
{
|
||||
Timeline = new Timeline();
|
||||
Renderer = new Renderer();
|
||||
ExpandedPropertyGroups = new List<string>();
|
||||
LayerEffectsList = new List<BaseLayerEffect>();
|
||||
|
||||
LayerEffectStore.LayerEffectAdded += LayerEffectStoreOnLayerEffectAdded;
|
||||
LayerEffectStore.LayerEffectRemoved += LayerEffectStoreOnLayerEffectRemoved;
|
||||
@ -68,7 +70,7 @@ namespace Artemis.Core
|
||||
LayerEffectEntity layerEffectEntity = new LayerEffectEntity
|
||||
{
|
||||
Id = layerEffect.EntityId,
|
||||
ProviderId = layerEffect.Descriptor.PlaceholderFor ?? layerEffect.ProviderId,
|
||||
ProviderId = layerEffect.Descriptor?.PlaceholderFor ?? layerEffect.ProviderId,
|
||||
EffectType = layerEffect.GetEffectTypeName(),
|
||||
Name = layerEffect.Name,
|
||||
Enabled = layerEffect.Enabled,
|
||||
@ -76,7 +78,7 @@ namespace Artemis.Core
|
||||
Order = layerEffect.Order
|
||||
};
|
||||
RenderElementEntity.LayerEffects.Add(layerEffectEntity);
|
||||
layerEffect.BaseProperties.ApplyToEntity();
|
||||
layerEffect.BaseProperties?.ApplyToEntity();
|
||||
}
|
||||
|
||||
// Conditions
|
||||
@ -290,8 +292,7 @@ namespace Artemis.Core
|
||||
private void LayerEffectStoreOnLayerEffectRemoved(object? sender, LayerEffectStoreEvent e)
|
||||
{
|
||||
// If effects provided by the plugin are on the element, replace them with placeholders
|
||||
List<BaseLayerEffect> pluginEffects = LayerEffectsList.Where(ef => ef.Descriptor.Provider != null &&
|
||||
ef.ProviderId == e.Registration.PluginFeature.Id).ToList();
|
||||
List<BaseLayerEffect> pluginEffects = LayerEffectsList.Where(ef => ef.ProviderId == e.Registration.PluginFeature.Id).ToList();
|
||||
foreach (BaseLayerEffect pluginEffect in pluginEffects)
|
||||
{
|
||||
LayerEffectEntity entity = RenderElementEntity.LayerEffects.First(en => en.Id == pluginEffect.EntityId);
|
||||
@ -323,13 +324,13 @@ namespace Artemis.Core
|
||||
protected set => SetAndNotify(ref _displayConditionMet, value);
|
||||
}
|
||||
|
||||
private DataModelConditionGroup _displayCondition;
|
||||
private DataModelConditionGroup? _displayCondition;
|
||||
private bool _displayConditionMet;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the root display condition group
|
||||
/// </summary>
|
||||
public DataModelConditionGroup DisplayCondition
|
||||
public DataModelConditionGroup? DisplayCondition
|
||||
{
|
||||
get => _displayCondition;
|
||||
set => SetAndNotify(ref _displayCondition, value);
|
||||
|
||||
@ -26,7 +26,7 @@ namespace Artemis.Core
|
||||
if (IsOpen)
|
||||
throw new ArtemisCoreException("Cannot open render context because it is already open");
|
||||
|
||||
if (!_valid)
|
||||
if (!_valid || Canvas == null)
|
||||
{
|
||||
SKRect pathBounds = path.Bounds;
|
||||
int width = (int) pathBounds.Width;
|
||||
@ -59,7 +59,7 @@ namespace Artemis.Core
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Renderer");
|
||||
|
||||
Canvas.Restore();
|
||||
Canvas?.Restore();
|
||||
Paint?.Dispose();
|
||||
Paint = null;
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ namespace Artemis.Core
|
||||
public class ArtemisDevice : CorePropertyChanged
|
||||
{
|
||||
private ReadOnlyCollection<ArtemisLed> _leds;
|
||||
private SKPath _renderPath;
|
||||
private SKPath? _renderPath;
|
||||
private SKRect _renderRectangle;
|
||||
|
||||
internal ArtemisDevice(IRGBDevice rgbDevice, DeviceProvider deviceProvider, ArtemisSurface surface)
|
||||
@ -23,7 +23,7 @@ namespace Artemis.Core
|
||||
DeviceProvider = deviceProvider;
|
||||
Surface = surface;
|
||||
DeviceEntity = new DeviceEntity();
|
||||
Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||
_leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||
|
||||
Rotation = 0;
|
||||
Scale = 1;
|
||||
@ -39,7 +39,7 @@ namespace Artemis.Core
|
||||
DeviceProvider = deviceProvider;
|
||||
Surface = surface;
|
||||
DeviceEntity = deviceEntity;
|
||||
Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||
_leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -54,7 +54,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets the path surrounding the device, sized to match the render scale
|
||||
/// </summary>
|
||||
public SKPath RenderPath
|
||||
public SKPath? RenderPath
|
||||
{
|
||||
get => _renderPath;
|
||||
private set => SetAndNotify(ref _renderPath, value);
|
||||
|
||||
@ -22,7 +22,7 @@ namespace Artemis.Core.Ninject
|
||||
|
||||
protected override ILogger CreateInstance(IContext context)
|
||||
{
|
||||
Type requestingType = context.Request.ParentContext?.Plan?.Type;
|
||||
Type? requestingType = context.Request.ParentContext?.Plan?.Type;
|
||||
if (requestingType != null)
|
||||
return Logger.ForContext(requestingType);
|
||||
return Logger;
|
||||
|
||||
@ -11,32 +11,32 @@ namespace Artemis.Core.DataModelExpansions
|
||||
/// <summary>
|
||||
/// Gets or sets the user-friendly name for this property, shown in the UI.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user-friendly description for this property, shown in the UI.
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the an optional prefix to show before displaying elements in the UI.
|
||||
/// </summary>
|
||||
public string Prefix { get; set; }
|
||||
public string? Prefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an optional affix to show behind displaying elements in the UI.
|
||||
/// </summary>
|
||||
public string Affix { get; set; }
|
||||
public string? Affix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an optional maximum value, this value is not enforced but used for percentage calculations.
|
||||
/// </summary>
|
||||
public object MaxValue { get; set; }
|
||||
public object? MaxValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an optional minimum value, this value is not enforced but used for percentage calculations.
|
||||
/// </summary>
|
||||
public object MinValue { get; set; }
|
||||
public object? MinValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether this property resets the max depth of the data model, defaults to true
|
||||
|
||||
@ -15,6 +15,16 @@ namespace Artemis.Core.DataModelExpansions
|
||||
{
|
||||
private readonly Dictionary<string, DataModel> _dynamicDataModels = new Dictionary<string, DataModel>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="DataModel" /> class
|
||||
/// </summary>
|
||||
protected DataModel()
|
||||
{
|
||||
// These are both set right after construction to keep the constructor of inherited classes clean
|
||||
Feature = null!;
|
||||
DataModelDescription = null!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin feature this data model belongs to
|
||||
/// </summary>
|
||||
@ -60,7 +70,7 @@ namespace Artemis.Core.DataModelExpansions
|
||||
/// <param name="key">The key of the child, must be unique to this data model</param>
|
||||
/// <param name="name">An optional name, if not provided the key will be used in a humanized form</param>
|
||||
/// <param name="description">An optional description</param>
|
||||
public T AddDynamicChild<T>(T dynamicDataModel, string key, string name = null, string description = null) where T : DataModel
|
||||
public T AddDynamicChild<T>(T dynamicDataModel, string key, string? name = null, string? description = null) where T : DataModel
|
||||
{
|
||||
if (dynamicDataModel == null)
|
||||
throw new ArgumentNullException(nameof(dynamicDataModel));
|
||||
@ -140,7 +150,7 @@ namespace Artemis.Core.DataModelExpansions
|
||||
/// <returns>If found, the dynamic data model otherwise <c>null</c></returns>
|
||||
public T? DynamicChild<T>(string key) where T : DataModel
|
||||
{
|
||||
_dynamicDataModels.TryGetValue(key, out DataModel value);
|
||||
_dynamicDataModels.TryGetValue(key, out DataModel? value);
|
||||
return value as T;
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ namespace Artemis.Core.DataModelExpansions
|
||||
/// </summary>
|
||||
public T DataModel
|
||||
{
|
||||
get => (T) InternalDataModel;
|
||||
get => InternalDataModel as T ?? throw new InvalidOperationException("Internal datamodel does not match the type of the data model");
|
||||
internal set => InternalDataModel = value;
|
||||
}
|
||||
|
||||
@ -49,11 +49,5 @@ namespace Artemis.Core.DataModelExpansions
|
||||
DataModel.DataModelDescription = GetDataModelDescription();
|
||||
base.InternalEnable();
|
||||
}
|
||||
|
||||
internal override void InternalDisable()
|
||||
{
|
||||
DataModel = null;
|
||||
base.InternalDisable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -31,7 +31,7 @@ namespace Artemis.Core.DeviceProviders
|
||||
/// A logger used by the device provider internally, ignore this
|
||||
/// </summary>
|
||||
[Inject]
|
||||
public ILogger Logger { get; set; }
|
||||
public ILogger? Logger { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Disable()
|
||||
|
||||
@ -10,10 +10,20 @@ namespace Artemis.Core.LayerBrushes
|
||||
{
|
||||
private LayerBrushType _brushType;
|
||||
private ILayerBrushConfigurationDialog? _configurationDialog;
|
||||
private LayerBrushDescriptor? _descriptor;
|
||||
private LayerBrushDescriptor _descriptor;
|
||||
private Layer _layer;
|
||||
private bool _supportsTransformation = true;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="BaseLayerBrush" /> class
|
||||
/// </summary>
|
||||
protected BaseLayerBrush()
|
||||
{
|
||||
// Both are set right after construction to keep the constructor of inherited classes clean
|
||||
_layer = null!;
|
||||
_descriptor = null!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layer this brush is applied to
|
||||
/// </summary>
|
||||
@ -26,7 +36,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);
|
||||
|
||||
@ -7,7 +7,7 @@ namespace Artemis.Core.LayerBrushes
|
||||
/// </summary>
|
||||
public abstract class PropertiesLayerBrush<T> : BaseLayerBrush where T : LayerPropertyGroup
|
||||
{
|
||||
private T _properties;
|
||||
private T _properties = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether all properties on this brush are initialized
|
||||
@ -35,7 +35,7 @@ namespace Artemis.Core.LayerBrushes
|
||||
internal void InitializeProperties()
|
||||
{
|
||||
Properties = Activator.CreateInstance<T>();
|
||||
Properties.GroupDescription ??= new PropertyGroupDescriptionAttribute {Name = Descriptor.DisplayName, Description = Descriptor.Description};
|
||||
Properties.GroupDescription = new PropertyGroupDescriptionAttribute {Name = Descriptor.DisplayName, Description = Descriptor.Description};
|
||||
Properties.LayerBrush = this;
|
||||
Properties.Initialize(Layer, "LayerBrush.", Descriptor.Provider);
|
||||
PropertiesInitialized = true;
|
||||
|
||||
@ -59,6 +59,7 @@ namespace Artemis.Core.LayerBrushes
|
||||
/// </summary>
|
||||
internal void CreateInstance(Layer layer)
|
||||
{
|
||||
if (layer == null) throw new ArgumentNullException(nameof(layer));
|
||||
if (layer.LayerBrush != null)
|
||||
throw new ArtemisCoreException("Layer already has an instantiated layer brush");
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ namespace Artemis.Core.LayerBrushes
|
||||
/// </summary>
|
||||
protected RgbNetLayerBrush()
|
||||
{
|
||||
LedGroup = new ListLedGroup();
|
||||
BrushType = LayerBrushType.RgbNet;
|
||||
SupportsTransformation = false;
|
||||
}
|
||||
@ -75,7 +76,7 @@ namespace Artemis.Core.LayerBrushes
|
||||
// Not used in this effect type
|
||||
internal override void InternalRender(SKCanvas canvas, SKRect bounds, SKPaint paint)
|
||||
{
|
||||
throw new NotImplementedException("RGB.NET layer effectes do not implement InternalRender");
|
||||
throw new NotImplementedException("RGB.NET layer effects do not implement InternalRender");
|
||||
}
|
||||
|
||||
private void LayerOnRenderPropertiesUpdated(object? sender, EventArgs e)
|
||||
|
||||
@ -9,7 +9,7 @@ namespace Artemis.Core.LayerEffects
|
||||
/// </summary>
|
||||
public abstract class BaseLayerEffect : CorePropertyChanged, IDisposable
|
||||
{
|
||||
private ILayerEffectConfigurationDialog _configurationDialog;
|
||||
private ILayerEffectConfigurationDialog? _configurationDialog;
|
||||
private LayerEffectDescriptor _descriptor;
|
||||
private bool _enabled;
|
||||
private Guid _entityId;
|
||||
@ -18,6 +18,15 @@ namespace Artemis.Core.LayerEffects
|
||||
private int _order;
|
||||
private RenderProfileElement _profileElement;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected BaseLayerEffect()
|
||||
{
|
||||
// These are set right after construction to keep the constructor of inherited classes clean
|
||||
_profileElement = null!;
|
||||
_descriptor = null!;
|
||||
_name = null!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique ID of this effect
|
||||
/// </summary>
|
||||
@ -76,7 +85,7 @@ namespace Artemis.Core.LayerEffects
|
||||
/// <summary>
|
||||
/// Gets the <see cref="LayerEffectDescriptor" /> that registered this effect
|
||||
/// </summary>
|
||||
public LayerEffectDescriptor? Descriptor
|
||||
public LayerEffectDescriptor Descriptor
|
||||
{
|
||||
get => _descriptor;
|
||||
internal set => SetAndNotify(ref _descriptor, value);
|
||||
@ -85,7 +94,7 @@ namespace Artemis.Core.LayerEffects
|
||||
/// <summary>
|
||||
/// Gets or sets a configuration dialog complementing the regular properties
|
||||
/// </summary>
|
||||
public ILayerEffectConfigurationDialog ConfigurationDialog
|
||||
public ILayerEffectConfigurationDialog? ConfigurationDialog
|
||||
{
|
||||
get => _configurationDialog;
|
||||
protected set => SetAndNotify(ref _configurationDialog, value);
|
||||
@ -94,12 +103,12 @@ namespace Artemis.Core.LayerEffects
|
||||
/// <summary>
|
||||
/// Gets the ID of the <see cref="LayerEffectProvider"/> 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;
|
||||
|
||||
internal string PropertyRootPath => $"LayerEffect.{EntityId}.{GetType().Name}.";
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ namespace Artemis.Core.LayerEffects
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class LayerEffect<T> : BaseLayerEffect where T : LayerPropertyGroup
|
||||
{
|
||||
private T _properties;
|
||||
private T _properties = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether all properties on this effect are initialized
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Artemis.Core.LayerEffects
|
||||
/// </summary>
|
||||
public class LayerEffectDescriptor
|
||||
{
|
||||
internal LayerEffectDescriptor(string displayName, string description, string icon, Type layerEffectType, LayerEffectProvider provider)
|
||||
internal LayerEffectDescriptor(string displayName, string description, string icon, Type? layerEffectType, LayerEffectProvider provider)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
Description = description;
|
||||
@ -39,12 +39,12 @@ namespace Artemis.Core.LayerEffects
|
||||
/// <summary>
|
||||
/// The type of the layer effect
|
||||
/// </summary>
|
||||
public Type LayerEffectType { get; }
|
||||
public Type? LayerEffectType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The plugin that provided this <see cref="LayerEffectDescriptor" />
|
||||
/// </summary>
|
||||
public LayerEffectProvider? Provider { get; }
|
||||
public LayerEffectProvider Provider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GUID this descriptor is acting as a placeholder for. If null, this descriptor is not a placeholder
|
||||
@ -66,8 +66,8 @@ namespace Artemis.Core.LayerEffects
|
||||
return;
|
||||
}
|
||||
|
||||
if (Provider == null)
|
||||
throw new ArtemisCoreException("Cannot create an instance of a layer effect because this descriptor is not a placeholder but is still missing its provider");
|
||||
if (LayerEffectType == null)
|
||||
throw new ArtemisCoreException("Cannot create an instance of a layer effect because this descriptor is not a placeholder but is still missing its LayerEffectType");
|
||||
|
||||
BaseLayerEffect effect = (BaseLayerEffect) Provider.Plugin.Kernel!.Get(LayerEffectType);
|
||||
effect.ProfileElement = renderElement;
|
||||
@ -85,7 +85,13 @@ namespace Artemis.Core.LayerEffects
|
||||
|
||||
private void CreatePlaceHolderInstance(RenderProfileElement renderElement, LayerEffectEntity entity)
|
||||
{
|
||||
PlaceholderLayerEffect effect = new PlaceholderLayerEffect(entity, PlaceholderFor) {ProfileElement = renderElement, Descriptor = this};
|
||||
if (PlaceholderFor == null)
|
||||
throw new ArtemisCoreException("Cannot create a placeholder instance using a layer effect descriptor that is not a placeholder for anything");
|
||||
PlaceholderLayerEffect effect = new PlaceholderLayerEffect(entity, PlaceholderFor)
|
||||
{
|
||||
ProfileElement = renderElement,
|
||||
Descriptor = this
|
||||
};
|
||||
effect.Initialize();
|
||||
renderElement.ActivateLayerEffect(effect);
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ namespace Artemis.Core.Modules
|
||||
/// </summary>
|
||||
/// <param name="processName">The name of the process that must run</param>
|
||||
/// <param name="location">The location of where the process must be running from (optional)</param>
|
||||
public ProcessActivationRequirement(string processName, string location = null)
|
||||
public ProcessActivationRequirement(string? processName, string? location = null)
|
||||
{
|
||||
ProcessName = processName;
|
||||
Location = location;
|
||||
@ -25,12 +25,12 @@ namespace Artemis.Core.Modules
|
||||
/// <summary>
|
||||
/// The name of the process that must run
|
||||
/// </summary>
|
||||
public string ProcessName { get; set; }
|
||||
public string? ProcessName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The location of where the process must be running from
|
||||
/// </summary>
|
||||
public string Location { get; set; }
|
||||
public string? Location { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Evaluate()
|
||||
|
||||
@ -18,7 +18,7 @@ namespace Artemis.Core.Modules
|
||||
/// </summary>
|
||||
public T DataModel
|
||||
{
|
||||
get => (T) InternalDataModel;
|
||||
get => InternalDataModel as T ?? throw new InvalidOperationException("Internal datamodel does not match the type of the data model");
|
||||
internal set => InternalDataModel = value;
|
||||
}
|
||||
|
||||
@ -52,12 +52,6 @@ namespace Artemis.Core.Modules
|
||||
DataModel.DataModelDescription = GetDataModelDescription();
|
||||
base.InternalEnable();
|
||||
}
|
||||
|
||||
internal override void InternalDisable()
|
||||
{
|
||||
DataModel = null;
|
||||
base.InternalDisable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -6,12 +6,11 @@ namespace Artemis.Core.Modules
|
||||
public class ModuleTab<T> : ModuleTab where T : IModuleViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ModuleTab{T}" /> class
|
||||
/// Creates a new instance of the <see cref="ModuleTab{T}" /> class
|
||||
/// </summary>
|
||||
/// <param name="title">The title of the tab</param>
|
||||
public ModuleTab(string title)
|
||||
public ModuleTab(string title) : base(title)
|
||||
{
|
||||
Title = title;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -24,9 +23,13 @@ namespace Artemis.Core.Modules
|
||||
public abstract class ModuleTab
|
||||
{
|
||||
/// <summary>
|
||||
/// The module this tab belongs to
|
||||
/// Creates a new instance of the <see cref="ModuleTab" /> class
|
||||
/// </summary>
|
||||
internal Module Module { get; set; }
|
||||
/// <param name="title">The title of the tab</param>
|
||||
protected ModuleTab(string title)
|
||||
{
|
||||
Title = title;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The title of the tab
|
||||
|
||||
@ -22,7 +22,7 @@ namespace Artemis.Core.Modules
|
||||
/// </summary>
|
||||
public T DataModel
|
||||
{
|
||||
get => (T) InternalDataModel;
|
||||
get => InternalDataModel as T ?? throw new InvalidOperationException("Internal datamodel does not match the type of the data model");
|
||||
internal set => InternalDataModel = value;
|
||||
}
|
||||
|
||||
@ -83,7 +83,6 @@ namespace Artemis.Core.Modules
|
||||
{
|
||||
Deactivate(true);
|
||||
base.InternalDisable();
|
||||
DataModel = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,7 +181,7 @@ namespace Artemis.Core.Modules
|
||||
ProfileRendered(deltaTime, surface, canvas, canvasInfo);
|
||||
}
|
||||
|
||||
internal async Task ChangeActiveProfileAnimated(Profile profile, ArtemisSurface surface)
|
||||
internal async Task ChangeActiveProfileAnimated(Profile? profile, ArtemisSurface? surface)
|
||||
{
|
||||
if (profile != null && profile.Module != this)
|
||||
throw new ArtemisCoreException($"Cannot activate a profile of module {profile.Module} on a module of plugin {this}.");
|
||||
@ -204,12 +203,14 @@ namespace Artemis.Core.Modules
|
||||
await Task.Delay(50);
|
||||
}
|
||||
|
||||
internal void ChangeActiveProfile(Profile profile, ArtemisSurface surface)
|
||||
internal void ChangeActiveProfile(Profile? profile, ArtemisSurface? surface)
|
||||
{
|
||||
if (profile != null && profile.Module != this)
|
||||
throw new ArtemisCoreException($"Cannot activate a profile of module {profile.Module} on a module of plugin {this}.");
|
||||
if (!IsActivated)
|
||||
throw new ArtemisCoreException("Cannot activate a profile on a deactivated module");
|
||||
if (profile != null && surface == null)
|
||||
throw new ArtemisCoreException("If changing the active profile to a non-null profile, a surface is required");
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
@ -219,7 +220,7 @@ namespace Artemis.Core.Modules
|
||||
ActiveProfile?.Dispose();
|
||||
|
||||
ActiveProfile = profile;
|
||||
ActiveProfile?.Activate(surface);
|
||||
ActiveProfile?.Activate(surface!);
|
||||
}
|
||||
|
||||
OnActiveProfileChanged();
|
||||
@ -229,7 +230,7 @@ namespace Artemis.Core.Modules
|
||||
{
|
||||
base.Deactivate(isOverride);
|
||||
|
||||
Profile profile = ActiveProfile;
|
||||
Profile? profile = ActiveProfile;
|
||||
ActiveProfile = null;
|
||||
profile?.Dispose();
|
||||
}
|
||||
@ -249,7 +250,7 @@ namespace Artemis.Core.Modules
|
||||
/// <summary>
|
||||
/// Occurs when the <see cref="ActiveProfile" /> has changed
|
||||
/// </summary>
|
||||
public event EventHandler ActiveProfileChanged;
|
||||
public event EventHandler? ActiveProfileChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="ActiveProfileChanged" /> event
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@ -19,10 +20,11 @@ namespace Artemis.Core
|
||||
|
||||
private bool _isEnabled;
|
||||
|
||||
internal Plugin(PluginInfo info, DirectoryInfo directory)
|
||||
internal Plugin(PluginInfo info, DirectoryInfo directory, PluginEntity? pluginEntity)
|
||||
{
|
||||
Info = info;
|
||||
Directory = directory;
|
||||
Entity = pluginEntity ?? new PluginEntity {Id = Guid, IsEnabled = true};
|
||||
|
||||
_features = new List<PluginFeature>();
|
||||
}
|
||||
@ -42,6 +44,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public DirectoryInfo Directory { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins
|
||||
/// </summary>
|
||||
@ -91,7 +94,8 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
/// <param name="path">The path to resolve</param>
|
||||
/// <returns>An absolute path pointing to the provided relative path</returns>
|
||||
public string? ResolveRelativePath(string path)
|
||||
[return: NotNullIfNotNull("path")]
|
||||
public string? ResolveRelativePath(string? path)
|
||||
{
|
||||
return path == null ? null : Path.Combine(Directory.FullName, path);
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets the plugin that provides this feature
|
||||
/// </summary>
|
||||
public Plugin Plugin { get; internal set; }
|
||||
public Plugin Plugin { get; internal set; } = null!; // Will be set right after construction
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the plugin is enabled
|
||||
@ -41,7 +41,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public string Id => $"{GetType().FullName}-{Plugin.Guid.ToString().Substring(0, 8)}"; // Not as unique as a GUID but good enough and stays readable
|
||||
|
||||
internal PluginFeatureEntity Entity { get; set; }
|
||||
internal PluginFeatureEntity Entity { get; set; } = null!; // Will be set right after construction
|
||||
|
||||
/// <summary>
|
||||
/// Called when the feature is activated
|
||||
|
||||
@ -9,13 +9,13 @@ namespace Artemis.Core
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public class PluginInfo : CorePropertyChanged
|
||||
{
|
||||
private string _description;
|
||||
private string? _description;
|
||||
private Guid _guid;
|
||||
private string _icon;
|
||||
private string _main;
|
||||
private string _name;
|
||||
private Plugin _plugin;
|
||||
private Version _version;
|
||||
private string? _icon;
|
||||
private string _main = null!;
|
||||
private string _name = null!;
|
||||
private Plugin _plugin = null!;
|
||||
private Version _version = null!;
|
||||
|
||||
internal PluginInfo()
|
||||
{
|
||||
@ -45,7 +45,7 @@ namespace Artemis.Core
|
||||
/// A short description of the plugin
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public string Description
|
||||
public string? Description
|
||||
{
|
||||
get => _description;
|
||||
set => SetAndNotify(ref _description, value);
|
||||
@ -57,7 +57,7 @@ namespace Artemis.Core
|
||||
/// icons
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public string Icon
|
||||
public string? Icon
|
||||
{
|
||||
get => _icon;
|
||||
set => SetAndNotify(ref _icon, value);
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Artemis.Core.Properties;
|
||||
using Artemis.Storage.Entities.Plugins;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using Newtonsoft.Json;
|
||||
@ -27,11 +29,11 @@ namespace Artemis.Core
|
||||
Name = pluginSettingEntity.Name;
|
||||
try
|
||||
{
|
||||
Value = JsonConvert.DeserializeObject<T>(pluginSettingEntity.Value);
|
||||
_value = JsonConvert.DeserializeObject<T>(pluginSettingEntity.Value);
|
||||
}
|
||||
catch (JsonReaderException)
|
||||
{
|
||||
Value = default;
|
||||
_value = default!;
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +45,8 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// The value of the setting
|
||||
/// </summary>
|
||||
[AllowNull]
|
||||
[CanBeNull]
|
||||
public T Value
|
||||
{
|
||||
get => _value;
|
||||
@ -50,7 +54,7 @@ namespace Artemis.Core
|
||||
{
|
||||
if (Equals(_value, value)) return;
|
||||
|
||||
_value = value;
|
||||
_value = value!;
|
||||
OnSettingChanged();
|
||||
OnPropertyChanged(nameof(Value));
|
||||
|
||||
@ -94,12 +98,12 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Occurs when the value of the setting has been changed
|
||||
/// </summary>
|
||||
public event EventHandler SettingChanged;
|
||||
public event EventHandler? SettingChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the value of the setting has been saved
|
||||
/// </summary>
|
||||
public event EventHandler SettingSaved;
|
||||
public event EventHandler? SettingSaved;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Artemis.Core
|
||||
public class TimedUpdateRegistration : IDisposable
|
||||
{
|
||||
private DateTime _lastEvent;
|
||||
private Timer _timer;
|
||||
private Timer? _timer;
|
||||
private bool _disposed;
|
||||
private readonly object _lock = new object();
|
||||
|
||||
@ -53,12 +53,12 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets the action that gets called each time the update event fires
|
||||
/// </summary>
|
||||
public Action<double> Action { get; }
|
||||
public Action<double>? Action { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the task that gets called each time the update event fires
|
||||
/// </summary>
|
||||
public Func<double, Task> AsyncAction { get; }
|
||||
public Func<double, Task>? AsyncAction { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Starts calling the <see cref="Action" /> or <see cref="AsyncAction"/> at the configured <see cref="Interval" />
|
||||
|
||||
@ -22,9 +22,10 @@ SOFTWARE. */
|
||||
|
||||
using System;
|
||||
|
||||
// ReSharper disable InheritdocConsiderUsage
|
||||
|
||||
#pragma warning disable 1591
|
||||
#pragma warning disable 8618
|
||||
|
||||
// ReSharper disable InheritdocConsiderUsage
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||
|
||||
@ -60,7 +60,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets the bitmap used to sample the brush
|
||||
/// </summary>
|
||||
public SKBitmap Bitmap { get; private set; }
|
||||
public SKBitmap? Bitmap { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@ -94,6 +94,9 @@ namespace Artemis.Core
|
||||
|
||||
private void TakeCenter(IEnumerable<BrushRenderTarget> renderTargets)
|
||||
{
|
||||
if (Bitmap == null)
|
||||
return;
|
||||
|
||||
foreach (BrushRenderTarget renderTarget in renderTargets)
|
||||
{
|
||||
Point scaledLocation = renderTarget.Point * Scale;
|
||||
@ -104,6 +107,9 @@ namespace Artemis.Core
|
||||
|
||||
private void TakeSamples(IEnumerable<BrushRenderTarget> renderTargets)
|
||||
{
|
||||
if (Bitmap == null)
|
||||
return;
|
||||
|
||||
int sampleSize = _sampleSizeSetting.Value;
|
||||
int sampleDepth = Math.Sqrt(sampleSize).RoundToInt();
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ namespace Artemis.Core.Services
|
||||
/// </summary>
|
||||
internal class CoreService : ICoreService
|
||||
{
|
||||
internal static IKernel Kernel;
|
||||
internal static IKernel Kernel = null!;
|
||||
|
||||
private readonly Stopwatch _frameStopWatch;
|
||||
private readonly ILogger _logger;
|
||||
@ -32,10 +32,10 @@ namespace Artemis.Core.Services
|
||||
private readonly IProfileService _profileService;
|
||||
private readonly IRgbService _rgbService;
|
||||
private readonly ISurfaceService _surfaceService;
|
||||
private List<BaseDataModelExpansion> _dataModelExpansions;
|
||||
private List<Module> _modules;
|
||||
private List<BaseDataModelExpansion> _dataModelExpansions = new List<BaseDataModelExpansion>();
|
||||
private List<Module> _modules = new List<Module>();
|
||||
|
||||
// ReSharper disable once UnusedParameter.Local - Storage migration service is injected early to ensure it runs before anything else
|
||||
// ReSharper disable UnusedParameter.Local - Storage migration and module service are injected early to ensure it runs before anything else
|
||||
public CoreService(IKernel kernel, ILogger logger, StorageMigrationService _, ISettingsService settingsService, IPluginManagementService pluginManagementService,
|
||||
IRgbService rgbService, ISurfaceService surfaceService, IProfileService profileService, IModuleService moduleService)
|
||||
{
|
||||
@ -60,10 +60,11 @@ namespace Artemis.Core.Services
|
||||
_pluginManagementService.PluginEnabled += (sender, args) => UpdatePluginCache();
|
||||
_pluginManagementService.PluginDisabled += (sender, args) => UpdatePluginCache();
|
||||
}
|
||||
// ReSharper restore UnusedParameter.Local
|
||||
|
||||
public TimeSpan FrameTime { get; private set; }
|
||||
public bool ModuleRenderingDisabled { get; set; }
|
||||
public List<string> StartupArguments { get; set; }
|
||||
public List<string>? StartupArguments { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
@ -86,13 +87,10 @@ namespace Artemis.Core.Services
|
||||
|
||||
// Initialize the services
|
||||
_pluginManagementService.CopyBuiltInPlugins();
|
||||
_pluginManagementService.LoadPlugins(StartupArguments.Contains("--ignore-plugin-lock"));
|
||||
_pluginManagementService.LoadPlugins(StartupArguments != null && StartupArguments.Contains("--ignore-plugin-lock"));
|
||||
|
||||
ArtemisSurface surfaceConfig = _surfaceService.ActiveSurface;
|
||||
if (surfaceConfig != null)
|
||||
_logger.Information("Initialized with active surface entity {surfaceConfig}-{guid}", surfaceConfig.Name, surfaceConfig.EntityId);
|
||||
else
|
||||
_logger.Information("Initialized without an active surface entity");
|
||||
|
||||
PlayIntroAnimation();
|
||||
OnInitialized();
|
||||
@ -121,7 +119,7 @@ namespace Artemis.Core.Services
|
||||
FrameRendering += DrawOverlay;
|
||||
|
||||
// Stop rendering after the profile finishes (take 1 second extra in case of slow updates)
|
||||
TimeSpan introLength = intro.AnimationProfile.GetAllLayers().Max(l => l.Timeline.Length);
|
||||
TimeSpan introLength = intro.AnimationProfile.GetAllLayers().Max(l => l.Timeline.Length)!;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(introLength.Add(TimeSpan.FromSeconds(1)));
|
||||
@ -217,14 +215,14 @@ namespace Artemis.Core.Services
|
||||
if (_rgbService.IsRenderPaused)
|
||||
return;
|
||||
|
||||
OnFrameRendered(new FrameRenderedEventArgs(_rgbService.BitmapBrush, _rgbService.Surface));
|
||||
OnFrameRendered(new FrameRenderedEventArgs(_rgbService.BitmapBrush!, _rgbService.Surface));
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler Initialized;
|
||||
public event EventHandler<FrameRenderingEventArgs> FrameRendering;
|
||||
public event EventHandler<FrameRenderedEventArgs> FrameRendered;
|
||||
public event EventHandler? Initialized;
|
||||
public event EventHandler<FrameRenderingEventArgs>? FrameRendering;
|
||||
public event EventHandler<FrameRenderedEventArgs>? FrameRendered;
|
||||
|
||||
private void OnInitialized()
|
||||
{
|
||||
|
||||
@ -26,7 +26,7 @@ namespace Artemis.Core.Services
|
||||
/// <summary>
|
||||
/// Gets or sets a list of startup arguments
|
||||
/// </summary>
|
||||
List<string> StartupArguments { get; set; }
|
||||
List<string>? StartupArguments { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the core, only call once
|
||||
|
||||
@ -12,13 +12,13 @@ namespace Artemis.Core.Services
|
||||
/// Gets the current active module override. If set, all other modules are deactivated and only the
|
||||
/// <see cref="ActiveModuleOverride" /> is active.
|
||||
/// </summary>
|
||||
Module ActiveModuleOverride { get; }
|
||||
Module? ActiveModuleOverride { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Changes the current <see cref="ActiveModuleOverride" /> and deactivates all other modules
|
||||
/// </summary>
|
||||
/// <param name="overrideModule"></param>
|
||||
Task SetActiveModuleOverride(Module overrideModule);
|
||||
Task SetActiveModuleOverride(Module? overrideModule);
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates every enabled module's activation requirements and activates/deactivates modules accordingly
|
||||
|
||||
@ -17,7 +17,7 @@ namespace Artemis.Core.Services
|
||||
/// <summary>
|
||||
/// Gets the bitmap brush used to convert the rendered frame to LED-colors
|
||||
/// </summary>
|
||||
BitmapBrush BitmapBrush { get; }
|
||||
BitmapBrush? BitmapBrush { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scale the frames are rendered on, a scale of 1.0 means 1 pixel = 1mm
|
||||
|
||||
@ -149,9 +149,9 @@ namespace Artemis.Core.Services
|
||||
UpdateModulePriority(module, category, priority);
|
||||
}
|
||||
|
||||
public Module ActiveModuleOverride { get; private set; }
|
||||
public Module? ActiveModuleOverride { get; private set; }
|
||||
|
||||
public async Task SetActiveModuleOverride(Module overrideModule)
|
||||
public async Task SetActiveModuleOverride(Module? overrideModule)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@ -242,11 +242,9 @@ namespace Artemis.Core.Services
|
||||
throw new ArtemisCoreException("Cannot load a plugin that is already loaded");
|
||||
}
|
||||
|
||||
Plugin plugin = new Plugin(pluginInfo, directory);
|
||||
OnPluginLoading(new PluginEventArgs(plugin));
|
||||
|
||||
// Load the entity and fall back on creating a new one
|
||||
plugin.Entity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid) ?? new PluginEntity {Id = plugin.Guid, IsEnabled = true};
|
||||
Plugin plugin = new Plugin(pluginInfo, directory, _pluginRepository.GetPluginByGuid(pluginInfo.Guid));
|
||||
OnPluginLoading(new PluginEventArgs(plugin));
|
||||
|
||||
// Locate the main assembly entry
|
||||
string? mainFile = plugin.ResolveRelativePath(plugin.Info.Main);
|
||||
|
||||
@ -34,7 +34,7 @@ namespace Artemis.Core.Services
|
||||
return ConditionOperatorStore.GetForType(type, side).Select(r => r.ConditionOperator).ToList();
|
||||
}
|
||||
|
||||
public BaseConditionOperator GetConditionOperator(Guid operatorPluginGuid, string operatorType)
|
||||
public BaseConditionOperator? GetConditionOperator(Guid operatorPluginGuid, string operatorType)
|
||||
{
|
||||
return ConditionOperatorStore.Get(operatorPluginGuid, operatorType)?.ConditionOperator;
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ namespace Artemis.Core.Services
|
||||
return DataBindingModifierTypeStore.GetForType(type, part).Select(r => r.DataBindingModifierType).ToList();
|
||||
}
|
||||
|
||||
public BaseDataBindingModifierType GetModifierType(Guid modifierTypePluginGuid, string modifierType)
|
||||
public BaseDataBindingModifierType? GetModifierType(Guid modifierTypePluginGuid, string modifierType)
|
||||
{
|
||||
return DataBindingModifierTypeStore.Get(modifierTypePluginGuid, modifierType)?.DataBindingModifierType;
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Artemis.Core.Services
|
||||
public DataModelService(IPluginManagementService pluginManagementService)
|
||||
{
|
||||
// Add data models of already loaded plugins
|
||||
foreach (Module module in pluginManagementService.GetFeaturesOfType<Module>().Where(p => p.IsEnabled))
|
||||
foreach (Module module in pluginManagementService.GetFeaturesOfType<Module>().Where(p => p.IsEnabled && p.InternalDataModel != null))
|
||||
AddModuleDataModel(module);
|
||||
foreach (BaseDataModelExpansion dataModelExpansion in pluginManagementService.GetFeaturesOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled))
|
||||
AddDataModelExpansionDataModel(dataModelExpansion);
|
||||
@ -40,9 +40,9 @@ namespace Artemis.Core.Services
|
||||
return DataModelStore.GetAll().Select(d => d.DataModel).ToList();
|
||||
}
|
||||
|
||||
public T GetDataModel<T>() where T : DataModel
|
||||
public T? GetDataModel<T>() where T : DataModel
|
||||
{
|
||||
return (T) DataModelStore.GetAll().FirstOrDefault(d => d.DataModel is T)?.DataModel;
|
||||
return (T?) DataModelStore.GetAll().FirstOrDefault(d => d.DataModel is T)?.DataModel;
|
||||
}
|
||||
|
||||
public DataModel? GetPluginDataModel(PluginFeature pluginFeature)
|
||||
@ -61,8 +61,7 @@ namespace Artemis.Core.Services
|
||||
private void AddModuleDataModel(Module module)
|
||||
{
|
||||
if (module.InternalDataModel == null)
|
||||
return;
|
||||
|
||||
throw new ArtemisCoreException("Cannot add module data model that is not enabled");
|
||||
if (module.InternalDataModel.DataModelDescription == null)
|
||||
throw new ArtemisPluginFeatureException(module, "Module overrides GetDataModelDescription but returned null");
|
||||
|
||||
@ -72,6 +71,8 @@ namespace Artemis.Core.Services
|
||||
|
||||
private void AddDataModelExpansionDataModel(BaseDataModelExpansion dataModelExpansion)
|
||||
{
|
||||
if (dataModelExpansion.InternalDataModel == null)
|
||||
throw new ArtemisCoreException("Cannot add data model expansion that is not enabled");
|
||||
if (dataModelExpansion.InternalDataModel.DataModelDescription == null)
|
||||
throw new ArtemisPluginFeatureException(dataModelExpansion, "Data model expansion overrides GetDataModelDescription but returned null");
|
||||
|
||||
|
||||
@ -32,6 +32,6 @@ namespace Artemis.Core.Services
|
||||
/// </summary>
|
||||
/// <param name="operatorPluginGuid">The operator's plugin GUID</param>
|
||||
/// <param name="operatorType">The type name of the operator</param>
|
||||
BaseConditionOperator GetConditionOperator(Guid operatorPluginGuid, string operatorType);
|
||||
BaseConditionOperator? GetConditionOperator(Guid operatorPluginGuid, string operatorType);
|
||||
}
|
||||
}
|
||||
@ -33,6 +33,6 @@ namespace Artemis.Core.Services
|
||||
/// <param name="modifierTypePluginGuid">The modifier type's plugin GUID</param>
|
||||
/// <param name="modifierType">The type name of the modifier type</param>
|
||||
/// <returns></returns>
|
||||
BaseDataBindingModifierType GetModifierType(Guid modifierTypePluginGuid, string modifierType);
|
||||
BaseDataBindingModifierType? GetModifierType(Guid modifierTypePluginGuid, string modifierType);
|
||||
}
|
||||
}
|
||||
@ -29,7 +29,7 @@ namespace Artemis.Core.Services
|
||||
/// If found, returns the registered data model of type <typeparamref name="T" />
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the data model to find</typeparam>
|
||||
T GetDataModel<T>() where T : DataModel;
|
||||
T? GetDataModel<T>() where T : DataModel;
|
||||
|
||||
/// <summary>
|
||||
/// If found, returns the data model of the provided plugin
|
||||
|
||||
@ -34,7 +34,7 @@ namespace Artemis.Core.Services
|
||||
return LayerBrushStore.GetAll().Select(r => r.LayerBrushDescriptor).ToList();
|
||||
}
|
||||
|
||||
public LayerBrushDescriptor GetDefaultLayerBrush()
|
||||
public LayerBrushDescriptor? GetDefaultLayerBrush()
|
||||
{
|
||||
PluginSetting<LayerBrushReference> defaultReference = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference
|
||||
{
|
||||
@ -42,6 +42,8 @@ namespace Artemis.Core.Services
|
||||
BrushType = "ColorBrush"
|
||||
});
|
||||
|
||||
defaultReference.Value.LayerBrushProviderId ??= "Artemis.Plugins.LayerBrushes.Color.ColorBrushProvider-92a9d6ba";
|
||||
defaultReference.Value.BrushType ??= "ColorBrush";
|
||||
return LayerBrushStore.Get(defaultReference.Value.LayerBrushProviderId, defaultReference.Value.BrushType)?.LayerBrushDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ namespace Artemis.Core.Services
|
||||
private readonly PluginSetting<double> _renderScaleSetting;
|
||||
private readonly PluginSetting<int> _sampleSizeSetting;
|
||||
private readonly PluginSetting<int> _targetFrameRateSetting;
|
||||
private ListLedGroup _surfaceLedGroup;
|
||||
private ListLedGroup? _surfaceLedGroup;
|
||||
|
||||
public RgbService(ILogger logger, ISettingsService settingsService)
|
||||
{
|
||||
@ -41,7 +41,7 @@ namespace Artemis.Core.Services
|
||||
public RGBSurface Surface { get; set; }
|
||||
|
||||
public TimerUpdateTrigger UpdateTrigger { get; }
|
||||
public BitmapBrush BitmapBrush { get; private set; }
|
||||
public BitmapBrush? BitmapBrush { get; private set; }
|
||||
public IReadOnlyCollection<IRGBDevice> LoadedDevices => _loadedDevices.AsReadOnly();
|
||||
public double RenderScale => _renderScaleSetting.Value;
|
||||
public bool IsRenderPaused { get; set; }
|
||||
@ -109,7 +109,7 @@ namespace Artemis.Core.Services
|
||||
|
||||
public void UpdateSurfaceLedGroup()
|
||||
{
|
||||
if (_surfaceLedGroup == null)
|
||||
if (_surfaceLedGroup == null || BitmapBrush == null)
|
||||
{
|
||||
// Apply the application wide brush and decorator
|
||||
BitmapBrush = new BitmapBrush(new Scale(_renderScaleSetting.Value), _sampleSizeSetting);
|
||||
@ -126,10 +126,6 @@ namespace Artemis.Core.Services
|
||||
BitmapBrush.Scale = new Scale(_renderScaleSetting.Value);
|
||||
_surfaceLedGroup = new ListLedGroup(Surface.Leds) {Brush = BitmapBrush};
|
||||
}
|
||||
|
||||
lock (BitmapBrush)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDeviceLoaded(DeviceEventArgs e)
|
||||
|
||||
@ -14,7 +14,7 @@ namespace Artemis.Core.Services
|
||||
|
||||
public PluginSetting<T> GetSetting<T>(string name, T defaultValue = default)
|
||||
{
|
||||
return _pluginSettings.GetSetting(name, defaultValue);
|
||||
return _pluginSettings.GetSetting(name, defaultValue!);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -36,6 +36,40 @@ namespace Artemis.Core.Services
|
||||
public JsonSerializerSettings MementoSettings { get; set; } = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All};
|
||||
public JsonSerializerSettings ExportSettings { get; set; } = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All, Formatting = Formatting.Indented};
|
||||
|
||||
public ProfileDescriptor? GetLastActiveProfile(ProfileModule module)
|
||||
{
|
||||
List<ProfileEntity> moduleProfiles = _profileRepository.GetByModuleId(module.Id);
|
||||
if (!moduleProfiles.Any())
|
||||
return CreateProfileDescriptor(module, "Default");
|
||||
|
||||
ProfileEntity? profileEntity = moduleProfiles.FirstOrDefault(p => p.IsActive) ?? moduleProfiles.FirstOrDefault();
|
||||
return profileEntity == null ? null : new ProfileDescriptor(module, profileEntity);
|
||||
}
|
||||
|
||||
private void SaveActiveProfile(ProfileModule module)
|
||||
{
|
||||
if (module.ActiveProfile == null)
|
||||
return;
|
||||
|
||||
List<ProfileEntity> profileEntities = _profileRepository.GetByModuleId(module.Id);
|
||||
foreach (ProfileEntity profileEntity in profileEntities)
|
||||
{
|
||||
profileEntity.IsActive = module.ActiveProfile.EntityId == profileEntity.Id;
|
||||
_profileRepository.Save(profileEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates all missing LEDs on all currently active profiles
|
||||
/// </summary>
|
||||
/// <param name="surface"></param>
|
||||
private void ActiveProfilesPopulateLeds(ArtemisSurface surface)
|
||||
{
|
||||
List<ProfileModule> profileModules = _pluginManagementService.GetFeaturesOfType<ProfileModule>();
|
||||
foreach (ProfileModule profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList())
|
||||
profileModule.ActiveProfile?.PopulateLeds(surface); // Avoid race condition
|
||||
}
|
||||
|
||||
public List<ProfileDescriptor> GetProfileDescriptors(ProfileModule module)
|
||||
{
|
||||
List<ProfileEntity> profileEntities = _profileRepository.GetByModuleId(module.Id);
|
||||
@ -52,14 +86,14 @@ namespace Artemis.Core.Services
|
||||
|
||||
public void ActivateLastProfile(ProfileModule profileModule)
|
||||
{
|
||||
ProfileDescriptor activeProfile = GetLastActiveProfile(profileModule);
|
||||
ProfileDescriptor? activeProfile = GetLastActiveProfile(profileModule);
|
||||
if (activeProfile != null)
|
||||
ActivateProfile(activeProfile);
|
||||
}
|
||||
|
||||
public async Task ActivateLastProfileAnimated(ProfileModule profileModule)
|
||||
{
|
||||
ProfileDescriptor activeProfile = GetLastActiveProfile(profileModule);
|
||||
ProfileDescriptor? activeProfile = GetLastActiveProfile(profileModule);
|
||||
if (activeProfile != null)
|
||||
await ActivateProfileAnimated(activeProfile);
|
||||
}
|
||||
@ -196,7 +230,8 @@ namespace Artemis.Core.Services
|
||||
string top = profile.UndoStack.Pop();
|
||||
string memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
||||
profile.RedoStack.Push(memento);
|
||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings);
|
||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings)
|
||||
?? throw new InvalidOperationException("Failed to deserialize memento");
|
||||
|
||||
profile.Load();
|
||||
InstantiateProfile(profile);
|
||||
@ -220,7 +255,8 @@ namespace Artemis.Core.Services
|
||||
string top = profile.RedoStack.Pop();
|
||||
string memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
||||
profile.UndoStack.Push(memento);
|
||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings);
|
||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings)
|
||||
?? throw new InvalidOperationException("Failed to deserialize memento");
|
||||
|
||||
profile.Load();
|
||||
InstantiateProfile(profile);
|
||||
@ -246,7 +282,9 @@ namespace Artemis.Core.Services
|
||||
|
||||
public ProfileDescriptor ImportProfile(string json, ProfileModule profileModule)
|
||||
{
|
||||
ProfileEntity profileEntity = JsonConvert.DeserializeObject<ProfileEntity>(json, ExportSettings);
|
||||
ProfileEntity? profileEntity = JsonConvert.DeserializeObject<ProfileEntity>(json, ExportSettings);
|
||||
if (profileEntity == null)
|
||||
throw new ArtemisCoreException("Failed to import profile but JSON.NET threw no error :(");
|
||||
|
||||
// Assign a new GUID to make sure it is unique in case of a previous import of the same content
|
||||
profileEntity.UpdateGuid(Guid.NewGuid());
|
||||
@ -256,40 +294,6 @@ namespace Artemis.Core.Services
|
||||
return new ProfileDescriptor(profileModule, profileEntity);
|
||||
}
|
||||
|
||||
public ProfileDescriptor GetLastActiveProfile(ProfileModule module)
|
||||
{
|
||||
List<ProfileEntity> moduleProfiles = _profileRepository.GetByModuleId(module.Id);
|
||||
if (!moduleProfiles.Any())
|
||||
return CreateProfileDescriptor(module, "Default");
|
||||
|
||||
ProfileEntity profileEntity = moduleProfiles.FirstOrDefault(p => p.IsActive) ?? moduleProfiles.FirstOrDefault();
|
||||
return profileEntity == null ? null : new ProfileDescriptor(module, profileEntity);
|
||||
}
|
||||
|
||||
private void SaveActiveProfile(ProfileModule module)
|
||||
{
|
||||
if (module.ActiveProfile == null)
|
||||
return;
|
||||
|
||||
List<ProfileEntity> profileEntities = _profileRepository.GetByModuleId(module.Id);
|
||||
foreach (ProfileEntity profileEntity in profileEntities)
|
||||
{
|
||||
profileEntity.IsActive = module.ActiveProfile.EntityId == profileEntity.Id;
|
||||
_profileRepository.Save(profileEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates all missing LEDs on all currently active profiles
|
||||
/// </summary>
|
||||
/// <param name="surface"></param>
|
||||
private void ActiveProfilesPopulateLeds(ArtemisSurface surface)
|
||||
{
|
||||
List<ProfileModule> profileModules = _pluginManagementService.GetFeaturesOfType<ProfileModule>();
|
||||
foreach (ProfileModule profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList())
|
||||
profileModule.ActiveProfile.PopulateLeds(surface);
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void OnActiveSurfaceConfigurationSelected(object? sender, SurfaceConfigurationEventArgs e)
|
||||
|
||||
@ -28,6 +28,8 @@ namespace Artemis.Core.Services
|
||||
_surfaceConfigurations = new List<ArtemisSurface>();
|
||||
_renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.5);
|
||||
|
||||
// LoadFromRepository is guaranteed to set the ActiveSurface
|
||||
ActiveSurface = null!;
|
||||
LoadFromRepository();
|
||||
|
||||
_rgbService.DeviceLoaded += RgbServiceOnDeviceLoaded;
|
||||
@ -61,6 +63,7 @@ namespace Artemis.Core.Services
|
||||
|
||||
public void SetActiveSurfaceConfiguration(ArtemisSurface surface)
|
||||
{
|
||||
if (surface == null) throw new ArgumentNullException(nameof(surface));
|
||||
if (ActiveSurface == surface)
|
||||
return;
|
||||
|
||||
@ -81,11 +84,8 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
|
||||
// Apply the active surface entity to the devices
|
||||
if (ActiveSurface != null)
|
||||
{
|
||||
foreach (ArtemisDevice device in ActiveSurface.Devices)
|
||||
device.ApplyToRgbDevice();
|
||||
}
|
||||
|
||||
// Update the RGB service's graphics decorator to work with the new surface entity
|
||||
_rgbService.UpdateSurfaceLedGroup();
|
||||
@ -134,7 +134,7 @@ namespace Artemis.Core.Services
|
||||
ArtemisSurface surfaceConfiguration = new ArtemisSurface(_rgbService.Surface, surfaceEntity, _renderScaleSetting.Value);
|
||||
foreach (DeviceEntity position in surfaceEntity.DeviceEntities)
|
||||
{
|
||||
IRGBDevice device = _rgbService.Surface.Devices.FirstOrDefault(d => d.GetDeviceIdentifier() == position.DeviceIdentifier);
|
||||
IRGBDevice? device = _rgbService.Surface.Devices.FirstOrDefault(d => d.GetDeviceIdentifier() == position.DeviceIdentifier);
|
||||
if (device != null)
|
||||
{
|
||||
DeviceProvider deviceProvider = _pluginManagementService.GetDeviceProviderByDevice(device);
|
||||
@ -150,7 +150,7 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
|
||||
// When all surface configs are loaded, apply the active surface config
|
||||
ArtemisSurface active = SurfaceConfigurations.FirstOrDefault(c => c.IsActive);
|
||||
ArtemisSurface? active = SurfaceConfigurations.FirstOrDefault(c => c.IsActive);
|
||||
if (active != null)
|
||||
SetActiveSurfaceConfiguration(active);
|
||||
else
|
||||
@ -170,13 +170,13 @@ namespace Artemis.Core.Services
|
||||
private void AddDeviceIfMissing(IRGBDevice rgbDevice, ArtemisSurface surface)
|
||||
{
|
||||
string deviceIdentifier = rgbDevice.GetDeviceIdentifier();
|
||||
ArtemisDevice device = surface.Devices.FirstOrDefault(d => d.DeviceEntity.DeviceIdentifier == deviceIdentifier);
|
||||
ArtemisDevice? device = surface.Devices.FirstOrDefault(d => d.DeviceEntity.DeviceIdentifier == deviceIdentifier);
|
||||
|
||||
if (device != null)
|
||||
return;
|
||||
|
||||
// Find an existing device config and use that
|
||||
DeviceEntity existingDeviceConfig = surface.SurfaceEntity.DeviceEntities.FirstOrDefault(d => d.DeviceIdentifier == deviceIdentifier);
|
||||
DeviceEntity? existingDeviceConfig = surface.SurfaceEntity.DeviceEntities.FirstOrDefault(d => d.DeviceIdentifier == deviceIdentifier);
|
||||
if (existingDeviceConfig != null)
|
||||
{
|
||||
DeviceProvider deviceProvider = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice);
|
||||
@ -225,8 +225,8 @@ namespace Artemis.Core.Services
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler<SurfaceConfigurationEventArgs> ActiveSurfaceConfigurationSelected;
|
||||
public event EventHandler<SurfaceConfigurationEventArgs> SurfaceConfigurationUpdated;
|
||||
public event EventHandler<SurfaceConfigurationEventArgs>? ActiveSurfaceConfigurationSelected;
|
||||
public event EventHandler<SurfaceConfigurationEventArgs>? SurfaceConfigurationUpdated;
|
||||
|
||||
protected virtual void OnActiveSurfaceConfigurationChanged(SurfaceConfigurationEventArgs e)
|
||||
{
|
||||
|
||||
@ -10,6 +10,9 @@ namespace Artemis.Core
|
||||
|
||||
public static ConditionOperatorRegistration Add(BaseConditionOperator conditionOperator)
|
||||
{
|
||||
if (conditionOperator.Plugin == null)
|
||||
throw new ArtemisCoreException("Cannot add a condition operator to the store that is not related to a plugin");
|
||||
|
||||
ConditionOperatorRegistration registration;
|
||||
lock (Registrations)
|
||||
{
|
||||
@ -74,8 +77,8 @@ namespace Artemis.Core
|
||||
|
||||
#region Events
|
||||
|
||||
public static event EventHandler<ConditionOperatorStoreEvent> ConditionOperatorAdded;
|
||||
public static event EventHandler<ConditionOperatorStoreEvent> ConditionOperatorRemoved;
|
||||
public static event EventHandler<ConditionOperatorStoreEvent>? ConditionOperatorAdded;
|
||||
public static event EventHandler<ConditionOperatorStoreEvent>? ConditionOperatorRemoved;
|
||||
|
||||
private static void OnConditionOperatorAdded(ConditionOperatorStoreEvent e)
|
||||
{
|
||||
|
||||
@ -57,8 +57,8 @@ namespace Artemis.Core
|
||||
|
||||
#region Events
|
||||
|
||||
public static event EventHandler<DataModelStoreEvent> DataModelAdded;
|
||||
public static event EventHandler<DataModelStoreEvent> DataModelRemoved;
|
||||
public static event EventHandler<DataModelStoreEvent>? DataModelAdded;
|
||||
public static event EventHandler<DataModelStoreEvent>? DataModelRemoved;
|
||||
|
||||
private static void OnDataModelAdded(DataModelStoreEvent e)
|
||||
{
|
||||
|
||||
@ -58,8 +58,8 @@ namespace Artemis.Core
|
||||
|
||||
#region Events
|
||||
|
||||
public static event EventHandler<LayerBrushStoreEvent> LayerBrushAdded;
|
||||
public static event EventHandler<LayerBrushStoreEvent> LayerBrushRemoved;
|
||||
public static event EventHandler<LayerBrushStoreEvent>? LayerBrushAdded;
|
||||
public static event EventHandler<LayerBrushStoreEvent>? LayerBrushRemoved;
|
||||
|
||||
private static void OnLayerBrushAdded(LayerBrushStoreEvent e)
|
||||
{
|
||||
|
||||
@ -51,14 +51,14 @@ namespace Artemis.Core
|
||||
{
|
||||
lock (Registrations)
|
||||
{
|
||||
return Registrations.FirstOrDefault(d => d.PluginFeature.Id == providerId && d.LayerEffectDescriptor.LayerEffectType.Name == typeName);
|
||||
return Registrations.FirstOrDefault(d => d.PluginFeature.Id == providerId && d.LayerEffectDescriptor.LayerEffectType?.Name == typeName);
|
||||
}
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
public static event EventHandler<LayerEffectStoreEvent> LayerEffectAdded;
|
||||
public static event EventHandler<LayerEffectStoreEvent> LayerEffectRemoved;
|
||||
public static event EventHandler<LayerEffectStoreEvent>? LayerEffectAdded;
|
||||
public static event EventHandler<LayerEffectStoreEvent>? LayerEffectRemoved;
|
||||
|
||||
private static void OnLayerEffectAdded(LayerEffectStoreEvent e)
|
||||
{
|
||||
|
||||
@ -23,7 +23,7 @@ namespace Artemis.Core
|
||||
string arguments = "-Command \"& {Start-Sleep -s " + delay + "; (Get-Process 'Artemis.UI').kill()}";
|
||||
// If restart is required, start the executable again after the process was killed
|
||||
if (restart)
|
||||
arguments = "-Command \"& {Start-Sleep -s " + delay + "; (Get-Process 'Artemis.UI').kill(); Start-Process -FilePath '" + Process.GetCurrentProcess().MainModule.FileName + "'}\"";
|
||||
arguments = "-Command \"& {Start-Sleep -s " + delay + "; (Get-Process 'Artemis.UI').kill(); Start-Process -FilePath '" + Process.GetCurrentProcess().MainModule!.FileName + "'}\"";
|
||||
|
||||
ProcessStartInfo info = new ProcessStartInfo
|
||||
{
|
||||
@ -45,7 +45,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
/// <param name="url">The URL to open</param>
|
||||
/// <returns>The process created to open the URL</returns>
|
||||
public static Process OpenUrl(string url)
|
||||
public static Process? OpenUrl(string url)
|
||||
{
|
||||
ProcessStartInfo processInfo = new ProcessStartInfo
|
||||
{
|
||||
@ -61,7 +61,7 @@ namespace Artemis.Core
|
||||
/// <returns></returns>
|
||||
internal static string GetCurrentLocation()
|
||||
{
|
||||
return Process.GetCurrentProcess().MainModule.FileName;
|
||||
return Process.GetCurrentProcess().MainModule!.FileName!;
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
@ -6,7 +6,7 @@ namespace Artemis.Core
|
||||
{
|
||||
internal static class DeserializationLogger
|
||||
{
|
||||
private static ILogger _logger;
|
||||
private static ILogger? _logger;
|
||||
|
||||
public static void Initialize(IKernel kernel)
|
||||
{
|
||||
@ -15,7 +15,7 @@ namespace Artemis.Core
|
||||
|
||||
public static void LogPredicateDeserializationFailure(DataModelConditionPredicate dataModelConditionPredicate, JsonException exception)
|
||||
{
|
||||
_logger.Warning(
|
||||
_logger?.Warning(
|
||||
exception,
|
||||
"Failed to deserialize display condition predicate {left} {operator} {right}",
|
||||
dataModelConditionPredicate.Entity.LeftPath?.Path,
|
||||
@ -26,7 +26,7 @@ namespace Artemis.Core
|
||||
|
||||
public static void LogModifierDeserializationFailure(string modifierName, JsonSerializationException exception)
|
||||
{
|
||||
_logger.Warning(exception, "Failed to deserialize static parameter for modifier {modifierName}", modifierName);
|
||||
_logger?.Warning(exception, "Failed to deserialize static parameter for modifier {modifierName}", modifierName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ namespace Artemis.Core
|
||||
{
|
||||
// Create an expression that checks every part of the path for null
|
||||
// In the same iteration, create the accessor
|
||||
Expression condition = null;
|
||||
Expression? condition = null;
|
||||
foreach (string memberName in path.Split('.'))
|
||||
{
|
||||
BinaryExpression notNull = Expression.NotEqual(source, Expression.Constant(null));
|
||||
|
||||
@ -21,21 +21,19 @@ namespace Artemis.Core
|
||||
_logger = logger;
|
||||
_profileService = profileService;
|
||||
_surfaceService = surfaceService;
|
||||
CreateIntroProfile();
|
||||
|
||||
AnimationProfile = CreateIntroProfile();
|
||||
}
|
||||
|
||||
public Profile AnimationProfile { get; set; }
|
||||
|
||||
public void Render(double deltaTime, SKCanvas canvas)
|
||||
{
|
||||
if (AnimationProfile == null)
|
||||
return;
|
||||
|
||||
AnimationProfile.Update(deltaTime);
|
||||
AnimationProfile.Render(canvas);
|
||||
}
|
||||
|
||||
private void CreateIntroProfile()
|
||||
private Profile CreateIntroProfile()
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -44,24 +42,24 @@ namespace Artemis.Core
|
||||
ProfileEntity profileEntity = JsonConvert.DeserializeObject<ProfileEntity>(json);
|
||||
// Inject every LED on the surface into each layer
|
||||
foreach (LayerEntity profileEntityLayer in profileEntity.Layers)
|
||||
{
|
||||
profileEntityLayer.Leds.AddRange(_surfaceService.ActiveSurface.Devices.SelectMany(d => d.Leds).Select(l => new LedEntity
|
||||
{
|
||||
DeviceIdentifier = l.Device.RgbDevice.GetDeviceIdentifier(),
|
||||
LedName = l.RgbLed.Id.ToString()
|
||||
}));
|
||||
}
|
||||
|
||||
Profile profile = new Profile(new DummyModule(), profileEntity);
|
||||
profile.Activate(_surfaceService.ActiveSurface);
|
||||
|
||||
_profileService.InstantiateProfile(profile);
|
||||
AnimationProfile = profile;
|
||||
return profile;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warning(e, "Failed to load intro profile");
|
||||
}
|
||||
|
||||
return new Profile(new DummyModule(), "Intro");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,11 +10,11 @@ namespace Artemis.Core
|
||||
{
|
||||
Type type = typeof(TSource);
|
||||
|
||||
MemberExpression member = propertyLambda.Body as MemberExpression;
|
||||
MemberExpression? member = propertyLambda.Body as MemberExpression;
|
||||
if (member == null)
|
||||
throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.", propertyLambda));
|
||||
|
||||
PropertyInfo propInfo = member.Member as PropertyInfo;
|
||||
PropertyInfo? propInfo = member.Member as PropertyInfo;
|
||||
if (propInfo == null)
|
||||
throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.", propertyLambda));
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user