From a3cd32f6c4bc62f689af4ff5e05f9182cf92b202 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 16 Nov 2020 20:16:06 +0100 Subject: [PATCH] Core - Added XML comments to all remaining public members/methods Core - Refactored a lot of code for nullable reference types --- src/Artemis.Core/Artemis.Core.csproj | 1 + .../Converters/FloatDataBindingConverter.cs | 4 +- .../Converters/SKColorDataBindingConverter.cs | 3 + .../Trigonometry/CosecantModifierType.cs | 2 +- .../Trigonometry/CotangentModifierType.cs | 2 +- .../Trigonometry/SecantModifierType.cs | 2 +- .../Properties/ColorGradientLayerProperty.cs | 2 +- .../Properties/FloatLayerProperty.cs | 4 +- .../Properties/FloatRangeLayerProperty.cs | 10 +- .../Properties/IntLayerProperty.cs | 4 +- .../Properties/IntRangeLayerProperty.cs | 10 +- .../LayerBrushReferenceLayerProperty.cs | 4 +- .../Properties/SKColorLayerProperty.cs | 2 +- .../Properties/SKPointLayerProperty.cs | 6 +- .../Properties/SKSizeLayerProperty.cs | 6 +- .../Events/DeviceConfigurationEventArgs.cs | 3 + src/Artemis.Core/Events/DeviceEventArgs.cs | 3 + .../Events/DynamicDataModelEventArgs.cs | 7 + .../Events/FrameRenderedEventArgs.cs | 7 + .../Events/FrameRenderingEventArgs.cs | 17 +- .../Events/Plugins/PluginEventArgs.cs | 12 +- .../Events/Plugins/PluginFeatureEventArgs.cs | 12 +- .../DataBindingPropertyUpdatedEvent.cs | 6 +- .../Events/Profiles/LayerPropertyEventArgs.cs | 20 ++- .../LayerPropertyGroupUpdatingEventArgs.cs | 14 -- .../Exceptions/ArtemisPluginException.cs | 18 +- .../ArtemisPluginFeatureException.cs | 36 ++-- .../Exceptions/ArtemisPluginLockException.cs | 7 +- .../Extensions/DirectoryInfoExtensions.cs | 2 +- .../Extensions/DoubleExtensions.cs | 8 + .../Extensions/FloatExtensions.cs | 10 ++ .../Extensions/IEnumerableExtensions.cs | 6 +- .../Extensions/ProcessExtensions.cs | 10 +- .../Extensions/RgbDeviceExtensions.cs | 2 +- .../Extensions/RgbRectangleExtensions.cs | 18 -- .../Extensions/SKColorExtensions.cs | 22 ++- src/Artemis.Core/Extensions/TypeExtensions.cs | 32 +++- .../JsonConverters/ForgivingIntConverter.cs | 4 +- src/Artemis.Core/MVVM/CorePropertyChanged.cs | 2 +- .../Models/Profile/Colors/ColorGradient.cs | 21 +-- .../Profile/Colors/ColorGradientStop.cs | 34 +--- .../Abstract/BaseConditionOperator.cs | 12 +- .../Abstract/DataModelConditionPart.cs | 19 ++- .../Abstract/DataModelConditionPredicate.cs | 17 +- .../Conditions/DataModelConditionEvent.cs | 53 +++--- .../DataModelConditionEventPredicate.cs | 6 +- .../DataModelConditionGeneralPredicate.cs | 2 + .../Conditions/DataModelConditionGroup.cs | 6 +- .../Conditions/DataModelConditionList.cs | 4 +- .../DataModelConditionListPredicate.cs | 6 +- .../EventPredicateWrapperDataModel.cs | 7 +- .../Wrappers/ListPredicateWrapperDataModel.cs | 3 + .../Profile/DataBindings/DataBinding.cs | 35 ++-- .../DataBindings/DataBindingConverter.cs | 29 +++- .../DataBindings/DataBindingRegistration.cs | 12 +- .../DataBindings/IDataBindingRegistration.cs | 4 +- .../Conditional/ConditionalDataBinding.cs | 17 +- .../Modes/Conditional/DataBindingCondition.cs | 7 +- .../Direct/BaseDataBindingModifierType.cs | 22 ++- .../Modes/Direct/DataBindingModifier.cs | 31 ++-- .../DataBindings/Modes/DirectDataBinding.cs | 5 +- .../Models/Profile/DataModel/DataModelPath.cs | 10 +- .../Profile/DataModel/DataModelPathSegment.cs | 12 +- src/Artemis.Core/Models/Profile/Folder.cs | 125 +++++++------- src/Artemis.Core/Models/Profile/Layer.cs | 156 ++++++++++++------ .../Models/Profile/LayerBrushReference.cs | 11 +- .../Models/Profile/LayerGeneralProperties.cs | 20 +++ .../PropertyDescriptionAttribute.cs | 15 +- .../PropertyGroupDescriptionAttribute.cs | 7 +- .../Profile/LayerProperties/LayerProperty.cs | 145 +++++++++------- .../LayerProperties/LayerPropertyKeyFrame.cs | 4 +- .../Models/Profile/LayerPropertyGroup.cs | 46 ++++-- .../Profile/LayerTransformProperties.cs | 23 +++ src/Artemis.Core/Models/Profile/Profile.cs | 64 ++++--- .../Models/Profile/ProfileDescriptor.cs | 19 ++- .../Models/Profile/ProfileElement.cs | 34 +++- .../Profile/PropertiesProfileElement.cs | 6 - .../Models/Profile/RenderProfileElement.cs | 98 ++++++----- src/Artemis.Core/Models/Profile/Renderer.cs | 2 +- src/Artemis.Core/Models/Profile/Timeline.cs | 1 + .../Models/Surface/ArtemisDevice.cs | 65 +++++++- src/Artemis.Core/Models/Surface/ArtemisLed.cs | 22 ++- .../Models/Surface/ArtemisSurface.cs | 52 ++++-- .../Plugins/DataModelExpansions/DataModel.cs | 10 +- .../Plugins/IPluginConfigurationDialog.cs | 4 +- .../LayerBrushes/Internal/BaseLayerBrush.cs | 16 +- .../LayerBrushes/LayerBrushDescriptor.cs | 2 +- .../IEffectConfigurationViewModel.cs | 6 - .../ILayerEffectConfigurationDialog.cs | 3 + src/Artemis.Core/Plugins/Plugin.cs | 1 + .../Plugins/TimedUpdateRegistration.cs | 6 +- src/Artemis.Core/Services/CoreService.cs | 2 +- .../Interfaces/IPluginManagementService.cs | 6 +- .../Services/PluginManagementService.cs | 50 +++--- .../Services/Storage/SurfaceService.cs | 17 +- .../Stores/ConditionOperatorStore.cs | 2 +- .../Stores/DataBindingModifierTypeStore.cs | 9 +- src/Artemis.Core/Stores/DataModelStore.cs | 2 +- .../Utilities/CurrentProcessUtilities.cs | 10 +- .../Artemis.UI.Shared.csproj | 1 + .../Services/DataModelUIService.cs | 8 +- .../Services/ProfileEditorService.cs | 4 +- .../Behaviors/TreeViewSelectionBehavior.cs | 4 +- src/Artemis.UI/Bootstrapper.cs | 2 +- .../Settings/Debug/DeviceDebugViewModel.cs | 2 +- .../Tabs/Devices/DeviceSettingsViewModel.cs | 2 +- src/Artemis.sln.DotSettings | 1 + 107 files changed, 1150 insertions(+), 649 deletions(-) delete mode 100644 src/Artemis.Core/Events/Profiles/LayerPropertyGroupUpdatingEventArgs.cs delete mode 100644 src/Artemis.Core/Extensions/RgbRectangleExtensions.cs delete mode 100644 src/Artemis.Core/Models/Profile/PropertiesProfileElement.cs delete mode 100644 src/Artemis.Core/Plugins/LayerEffects/IEffectConfigurationViewModel.cs diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index 374cb130f..e597d75d3 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -13,6 +13,7 @@ x64 bin\x64\Debug\Artemis.Core.xml + 1701;1702 diff --git a/src/Artemis.Core/DefaultTypes/DataBindings/Converters/FloatDataBindingConverter.cs b/src/Artemis.Core/DefaultTypes/DataBindings/Converters/FloatDataBindingConverter.cs index 9ffb4ec37..b076134bb 100644 --- a/src/Artemis.Core/DefaultTypes/DataBindings/Converters/FloatDataBindingConverter.cs +++ b/src/Artemis.Core/DefaultTypes/DataBindings/Converters/FloatDataBindingConverter.cs @@ -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); diff --git a/src/Artemis.Core/DefaultTypes/DataBindings/Converters/SKColorDataBindingConverter.cs b/src/Artemis.Core/DefaultTypes/DataBindings/Converters/SKColorDataBindingConverter.cs index 003e06fa0..6b708e088 100644 --- a/src/Artemis.Core/DefaultTypes/DataBindings/Converters/SKColorDataBindingConverter.cs +++ b/src/Artemis.Core/DefaultTypes/DataBindings/Converters/SKColorDataBindingConverter.cs @@ -5,6 +5,9 @@ namespace Artemis.Core /// public class SKColorDataBindingConverter : DataBindingConverter { + /// + /// Creates a new instance of the class + /// public SKColorDataBindingConverter() { SupportsInterpolate = true; diff --git a/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/CosecantModifierType.cs b/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/CosecantModifierType.cs index 201bb6f8b..bc79c9b79 100644 --- a/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/CosecantModifierType.cs +++ b/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/CosecantModifierType.cs @@ -5,7 +5,7 @@ namespace Artemis.Core internal class CosecantModifierType : DataBindingModifierType { 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"; diff --git a/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/CotangentModifierType.cs b/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/CotangentModifierType.cs index dc95afffe..39e514aa3 100644 --- a/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/CotangentModifierType.cs +++ b/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/CotangentModifierType.cs @@ -5,7 +5,7 @@ namespace Artemis.Core internal class CotangentModifierType : DataBindingModifierType { 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"; diff --git a/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/SecantModifierType.cs b/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/SecantModifierType.cs index f597ad762..c4790f2dd 100644 --- a/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/SecantModifierType.cs +++ b/src/Artemis.Core/DefaultTypes/DataBindings/Modifiers/Numbers/Trigonometry/SecantModifierType.cs @@ -5,7 +5,7 @@ namespace Artemis.Core internal class SecantModifierType : DataBindingModifierType { 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"; diff --git a/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs index e76348410..e3c6fbccf 100644 --- a/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs +++ b/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs @@ -25,7 +25,7 @@ throw new ArtemisCoreException("Color Gradients do not support keyframes."); } - private void OnCurrentValueSet(object sender, LayerPropertyEventArgs e) + private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs e) { // Don't allow color gradients to be null if (BaseValue == null) diff --git a/src/Artemis.Core/DefaultTypes/Properties/FloatLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/FloatLayerProperty.cs index b9fc3cfd7..55221deaf 100644 --- a/src/Artemis.Core/DefaultTypes/Properties/FloatLayerProperty.cs +++ b/src/Artemis.Core/DefaultTypes/Properties/FloatLayerProperty.cs @@ -27,8 +27,8 @@ /// 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; } } } \ No newline at end of file diff --git a/src/Artemis.Core/DefaultTypes/Properties/FloatRangeLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/FloatRangeLayerProperty.cs index 1cb7c321a..8fa32a603 100644 --- a/src/Artemis.Core/DefaultTypes/Properties/FloatRangeLayerProperty.cs +++ b/src/Artemis.Core/DefaultTypes/Properties/FloatRangeLayerProperty.cs @@ -14,15 +14,15 @@ /// 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 e) + private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs e) { // Don't allow the int range to be null BaseValue ??= DefaultValue ?? new FloatRange(0, 0); diff --git a/src/Artemis.Core/DefaultTypes/Properties/IntLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/IntLayerProperty.cs index 3ab64c02c..7edd5241d 100644 --- a/src/Artemis.Core/DefaultTypes/Properties/IntLayerProperty.cs +++ b/src/Artemis.Core/DefaultTypes/Properties/IntLayerProperty.cs @@ -37,8 +37,8 @@ namespace Artemis.Core /// 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); } } } \ No newline at end of file diff --git a/src/Artemis.Core/DefaultTypes/Properties/IntRangeLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/IntRangeLayerProperty.cs index dc9503520..7c7ef0240 100644 --- a/src/Artemis.Core/DefaultTypes/Properties/IntRangeLayerProperty.cs +++ b/src/Artemis.Core/DefaultTypes/Properties/IntRangeLayerProperty.cs @@ -14,15 +14,15 @@ /// 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 e) + private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs e) { // Don't allow the int range to be null BaseValue ??= DefaultValue ?? new IntRange(0, 0); diff --git a/src/Artemis.Core/DefaultTypes/Properties/LayerBrushReferenceLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/LayerBrushReferenceLayerProperty.cs index 04eb19730..9bbd77eac 100644 --- a/src/Artemis.Core/DefaultTypes/Properties/LayerBrushReferenceLayerProperty.cs +++ b/src/Artemis.Core/DefaultTypes/Properties/LayerBrushReferenceLayerProperty.cs @@ -3,7 +3,7 @@ /// /// A special layer property used to configure the selected layer brush /// - public class LayerBrushReferenceLayerProperty : LayerProperty + public class LayerBrushReferenceLayerProperty : LayerProperty { internal LayerBrushReferenceLayerProperty() { @@ -14,7 +14,7 @@ /// /// Implicitly converts an to an /// - public static implicit operator LayerBrushReference(LayerBrushReferenceLayerProperty p) + public static implicit operator LayerBrushReference?(LayerBrushReferenceLayerProperty p) { return p.CurrentValue; } diff --git a/src/Artemis.Core/DefaultTypes/Properties/SKColorLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/SKColorLayerProperty.cs index a7663a789..366c4aa49 100644 --- a/src/Artemis.Core/DefaultTypes/Properties/SKColorLayerProperty.cs +++ b/src/Artemis.Core/DefaultTypes/Properties/SKColorLayerProperty.cs @@ -23,7 +23,7 @@ namespace Artemis.Core /// protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased) { - CurrentValue = CurrentKeyframe.Value.Interpolate(NextKeyframe.Value, keyframeProgressEased); + CurrentValue = CurrentKeyframe!.Value.Interpolate(NextKeyframe!.Value, keyframeProgressEased); } } } \ No newline at end of file diff --git a/src/Artemis.Core/DefaultTypes/Properties/SKPointLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/SKPointLayerProperty.cs index 03c35baf2..74befb209 100644 --- a/src/Artemis.Core/DefaultTypes/Properties/SKPointLayerProperty.cs +++ b/src/Artemis.Core/DefaultTypes/Properties/SKPointLayerProperty.cs @@ -22,9 +22,9 @@ namespace Artemis.Core /// 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); } } } \ No newline at end of file diff --git a/src/Artemis.Core/DefaultTypes/Properties/SKSizeLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/SKSizeLayerProperty.cs index 9a3707f3a..0d98286b6 100644 --- a/src/Artemis.Core/DefaultTypes/Properties/SKSizeLayerProperty.cs +++ b/src/Artemis.Core/DefaultTypes/Properties/SKSizeLayerProperty.cs @@ -22,9 +22,9 @@ namespace Artemis.Core /// 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); } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/DeviceConfigurationEventArgs.cs b/src/Artemis.Core/Events/DeviceConfigurationEventArgs.cs index 45c31fb7e..dbc66515e 100644 --- a/src/Artemis.Core/Events/DeviceConfigurationEventArgs.cs +++ b/src/Artemis.Core/Events/DeviceConfigurationEventArgs.cs @@ -12,6 +12,9 @@ namespace Artemis.Core Surface = surface; } + /// + /// Gets the active surface at the time the event fired + /// public ArtemisSurface Surface { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/DeviceEventArgs.cs b/src/Artemis.Core/Events/DeviceEventArgs.cs index 0f306793a..3999e9f83 100644 --- a/src/Artemis.Core/Events/DeviceEventArgs.cs +++ b/src/Artemis.Core/Events/DeviceEventArgs.cs @@ -13,6 +13,9 @@ namespace Artemis.Core Device = device; } + /// + /// Gets the device this event is related to + /// public IRGBDevice Device { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/DynamicDataModelEventArgs.cs b/src/Artemis.Core/Events/DynamicDataModelEventArgs.cs index 77fb13b54..c1b335adc 100644 --- a/src/Artemis.Core/Events/DynamicDataModelEventArgs.cs +++ b/src/Artemis.Core/Events/DynamicDataModelEventArgs.cs @@ -14,7 +14,14 @@ namespace Artemis.Core Key = key; } + /// + /// Gets the dynamic data model + /// public DataModel DynamicDataModel { get; } + + /// + /// Gets the key of the dynamic data model on the parent + /// public string Key { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/FrameRenderedEventArgs.cs b/src/Artemis.Core/Events/FrameRenderedEventArgs.cs index bbe43b54b..5911591d5 100644 --- a/src/Artemis.Core/Events/FrameRenderedEventArgs.cs +++ b/src/Artemis.Core/Events/FrameRenderedEventArgs.cs @@ -14,7 +14,14 @@ namespace Artemis.Core RgbSurface = rgbSurface; } + /// + /// Gets the bitmap brush used to render this frame + /// public BitmapBrush BitmapBrush { get; } + + /// + /// Gets the RGB surface used to render this frame + /// public RGBSurface RgbSurface { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/FrameRenderingEventArgs.cs b/src/Artemis.Core/Events/FrameRenderingEventArgs.cs index 2fea69f08..1b1c0e747 100644 --- a/src/Artemis.Core/Events/FrameRenderingEventArgs.cs +++ b/src/Artemis.Core/Events/FrameRenderingEventArgs.cs @@ -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 /// public class FrameRenderingEventArgs : EventArgs { - internal FrameRenderingEventArgs(List 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 Modules { get; } + /// + /// Gets the canvas this frame is rendering on + /// public SKCanvas Canvas { get; } + + /// + /// Gets the delta time since the last frame was rendered + /// public double DeltaTime { get; } + + /// + /// Gets the RGB surface used to render this frame + /// public RGBSurface RgbSurface { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/Plugins/PluginEventArgs.cs b/src/Artemis.Core/Events/Plugins/PluginEventArgs.cs index 48e4ec7db..aa21536bc 100644 --- a/src/Artemis.Core/Events/Plugins/PluginEventArgs.cs +++ b/src/Artemis.Core/Events/Plugins/PluginEventArgs.cs @@ -2,17 +2,19 @@ namespace Artemis.Core { + /// + /// Provides data about plugin related events + /// public class PluginEventArgs : EventArgs { - public PluginEventArgs() - { - } - - public PluginEventArgs(Plugin plugin) + internal PluginEventArgs(Plugin plugin) { Plugin = plugin; } + /// + /// Gets the plugin this event is related to + /// public Plugin Plugin { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/Plugins/PluginFeatureEventArgs.cs b/src/Artemis.Core/Events/Plugins/PluginFeatureEventArgs.cs index 288e46088..8d33d0f4b 100644 --- a/src/Artemis.Core/Events/Plugins/PluginFeatureEventArgs.cs +++ b/src/Artemis.Core/Events/Plugins/PluginFeatureEventArgs.cs @@ -2,17 +2,19 @@ namespace Artemis.Core { + /// + /// Provides data about plugin feature related events + /// public class PluginFeatureEventArgs : EventArgs { - public PluginFeatureEventArgs() - { - } - - public PluginFeatureEventArgs(PluginFeature pluginFeature) + internal PluginFeatureEventArgs(PluginFeature pluginFeature) { PluginFeature = pluginFeature; } + /// + /// Gets the plugin feature this event is related to + /// public PluginFeature PluginFeature { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/Profiles/DataBindingPropertyUpdatedEvent.cs b/src/Artemis.Core/Events/Profiles/DataBindingPropertyUpdatedEvent.cs index 52c8a99fa..33ea09229 100644 --- a/src/Artemis.Core/Events/Profiles/DataBindingPropertyUpdatedEvent.cs +++ b/src/Artemis.Core/Events/Profiles/DataBindingPropertyUpdatedEvent.cs @@ -2,9 +2,13 @@ namespace Artemis.Core { + /// + /// Provides data for the event. + /// + /// public class DataBindingPropertyUpdatedEvent : EventArgs { - public DataBindingPropertyUpdatedEvent(T value) + internal DataBindingPropertyUpdatedEvent(T value) { Value = value; } diff --git a/src/Artemis.Core/Events/Profiles/LayerPropertyEventArgs.cs b/src/Artemis.Core/Events/Profiles/LayerPropertyEventArgs.cs index 296de8310..e08331b9a 100644 --- a/src/Artemis.Core/Events/Profiles/LayerPropertyEventArgs.cs +++ b/src/Artemis.Core/Events/Profiles/LayerPropertyEventArgs.cs @@ -2,23 +2,35 @@ namespace Artemis.Core { + /// + /// Provides strongly typed data for layer property events of type . + /// public class LayerPropertyEventArgs : EventArgs { - public LayerPropertyEventArgs(LayerProperty layerProperty) + internal LayerPropertyEventArgs(LayerProperty layerProperty) { LayerProperty = layerProperty; } + /// + /// Gets the layer property this event is related to + /// public LayerProperty LayerProperty { get; } - } - + } + + /// + /// Provides data for layer property events. + /// public class LayerPropertyEventArgs : EventArgs { - public LayerPropertyEventArgs(ILayerProperty layerProperty) + internal LayerPropertyEventArgs(ILayerProperty layerProperty) { LayerProperty = layerProperty; } + /// + /// Gets the layer property this event is related to + /// public ILayerProperty LayerProperty { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/Profiles/LayerPropertyGroupUpdatingEventArgs.cs b/src/Artemis.Core/Events/Profiles/LayerPropertyGroupUpdatingEventArgs.cs deleted file mode 100644 index fc0e51cbe..000000000 --- a/src/Artemis.Core/Events/Profiles/LayerPropertyGroupUpdatingEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Artemis.Core -{ - public class LayerPropertyGroupUpdatingEventArgs : EventArgs - { - public LayerPropertyGroupUpdatingEventArgs(double deltaTime) - { - DeltaTime = deltaTime; - } - - public double DeltaTime { get; } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs index 84c33d8ad..5195a9524 100644 --- a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs +++ b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs @@ -2,31 +2,37 @@ namespace Artemis.Core { + /// + /// An exception thrown when a plugin-related error occurs + /// 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; } + /// + /// Gets the plugin the error is related to + /// + public Plugin? Plugin { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Exceptions/ArtemisPluginFeatureException.cs b/src/Artemis.Core/Exceptions/ArtemisPluginFeatureException.cs index e15e7e313..3e1766bd7 100644 --- a/src/Artemis.Core/Exceptions/ArtemisPluginFeatureException.cs +++ b/src/Artemis.Core/Exceptions/ArtemisPluginFeatureException.cs @@ -2,23 +2,29 @@ namespace Artemis.Core { + /// + /// An exception thrown when a plugin feature-related error occurs + /// 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; + } + + /// + /// Gets the plugin feature the error is related to + /// 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; - } } } \ No newline at end of file diff --git a/src/Artemis.Core/Exceptions/ArtemisPluginLockException.cs b/src/Artemis.Core/Exceptions/ArtemisPluginLockException.cs index c6cb4c8f0..e95d27272 100644 --- a/src/Artemis.Core/Exceptions/ArtemisPluginLockException.cs +++ b/src/Artemis.Core/Exceptions/ArtemisPluginLockException.cs @@ -2,13 +2,16 @@ namespace Artemis.Core { + /// + /// An exception thrown when a plugin lock file error occurs + /// 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." diff --git a/src/Artemis.Core/Extensions/DirectoryInfoExtensions.cs b/src/Artemis.Core/Extensions/DirectoryInfoExtensions.cs index f1f0a7d68..fda99d3b5 100644 --- a/src/Artemis.Core/Extensions/DirectoryInfoExtensions.cs +++ b/src/Artemis.Core/Extensions/DirectoryInfoExtensions.cs @@ -2,7 +2,7 @@ namespace Artemis.Core { - public static class DirectoryInfoExtensions + internal static class DirectoryInfoExtensions { public static void CopyFilesRecursively(this DirectoryInfo source, DirectoryInfo target) { diff --git a/src/Artemis.Core/Extensions/DoubleExtensions.cs b/src/Artemis.Core/Extensions/DoubleExtensions.cs index 42cfcfbc1..796f247fb 100644 --- a/src/Artemis.Core/Extensions/DoubleExtensions.cs +++ b/src/Artemis.Core/Extensions/DoubleExtensions.cs @@ -3,8 +3,16 @@ using System.Runtime.CompilerServices; namespace Artemis.Core { + /// + /// A static class providing extensions + /// public static class DoubleExtensions { + /// + /// Rounds the provided number away to zero and casts the result to an + /// + /// The number to round + /// The rounded number as an integer [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int RoundToInt(this double number) { diff --git a/src/Artemis.Core/Extensions/FloatExtensions.cs b/src/Artemis.Core/Extensions/FloatExtensions.cs index a6c5ba7b8..aabe25497 100644 --- a/src/Artemis.Core/Extensions/FloatExtensions.cs +++ b/src/Artemis.Core/Extensions/FloatExtensions.cs @@ -1,9 +1,19 @@ using System; +using System.Runtime.CompilerServices; namespace Artemis.Core { + /// + /// A static class providing extensions + /// public static class FloatExtensions { + /// + /// Rounds the provided number away to zero and casts the result to an + /// + /// The number to round + /// The rounded number as an integer + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int RoundToInt(this float number) { return (int) Math.Round(number, MidpointRounding.AwayFromZero); diff --git a/src/Artemis.Core/Extensions/IEnumerableExtensions.cs b/src/Artemis.Core/Extensions/IEnumerableExtensions.cs index d0e591363..980240c35 100644 --- a/src/Artemis.Core/Extensions/IEnumerableExtensions.cs +++ b/src/Artemis.Core/Extensions/IEnumerableExtensions.cs @@ -24,6 +24,10 @@ using System.Collections.Generic; namespace Artemis.Core { + /// + /// A static class providing extensions + /// + // ReSharper disable once InconsistentNaming public static class IEnumerableExtensions { /// @@ -46,7 +50,7 @@ namespace Artemis.Core public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) { - return source.DistinctBy(keySelector, null); + return source.DistinctBy(keySelector, null!); } /// diff --git a/src/Artemis.Core/Extensions/ProcessExtensions.cs b/src/Artemis.Core/Extensions/ProcessExtensions.cs index 39d1083ee..eb02a3c75 100644 --- a/src/Artemis.Core/Extensions/ProcessExtensions.cs +++ b/src/Artemis.Core/Extensions/ProcessExtensions.cs @@ -5,8 +5,16 @@ using System.Text; namespace Artemis.Core { + /// + /// A static class providing extensions + /// public static class ProcessExtensions { + /// + /// Gets the file name of the given process + /// + /// The process + /// The filename of the given process 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")] diff --git a/src/Artemis.Core/Extensions/RgbDeviceExtensions.cs b/src/Artemis.Core/Extensions/RgbDeviceExtensions.cs index 98a1eb7a2..1e15c8fab 100644 --- a/src/Artemis.Core/Extensions/RgbDeviceExtensions.cs +++ b/src/Artemis.Core/Extensions/RgbDeviceExtensions.cs @@ -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) { diff --git a/src/Artemis.Core/Extensions/RgbRectangleExtensions.cs b/src/Artemis.Core/Extensions/RgbRectangleExtensions.cs deleted file mode 100644 index 6f58a0e46..000000000 --- a/src/Artemis.Core/Extensions/RgbRectangleExtensions.cs +++ /dev/null @@ -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() - ); - } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Extensions/SKColorExtensions.cs b/src/Artemis.Core/Extensions/SKColorExtensions.cs index 09202b9e4..819e09045 100644 --- a/src/Artemis.Core/Extensions/SKColorExtensions.cs +++ b/src/Artemis.Core/Extensions/SKColorExtensions.cs @@ -4,14 +4,28 @@ using SkiaSharp; namespace Artemis.Core { - // ReSharper disable once InconsistentNaming - I didn't come up with SKColor + /// + /// A static class providing extensions + /// public static class SKColorExtensions { + /// + /// Converts hte SKColor to an RGB.NET color + /// + /// The color to convert + /// The RGB.NET color public static Color ToRgbColor(this SKColor color) { return new Color(color.Alpha, color.Red, color.Green, color.Blue); } + /// + /// Interpolates a color between the and color. + /// + /// The first color + /// The second color + /// A value between 0 and 1 + /// The interpolated color public static SKColor Interpolate(this SKColor from, SKColor to, float progress) { int redDiff = to.Red - from.Red; @@ -27,6 +41,12 @@ namespace Artemis.Core ); } + /// + /// Adds the two colors together + /// + /// The first color + /// The second color + /// The sum of the two colors public static SKColor Sum(this SKColor a, SKColor b) { return new SKColor( diff --git a/src/Artemis.Core/Extensions/TypeExtensions.cs b/src/Artemis.Core/Extensions/TypeExtensions.cs index b485a4865..7bfbc5260 100644 --- a/src/Artemis.Core/Extensions/TypeExtensions.cs +++ b/src/Artemis.Core/Extensions/TypeExtensions.cs @@ -6,6 +6,9 @@ using Humanizer; namespace Artemis.Core { + /// + /// A static class providing extensions + /// public static class TypeExtensions { private static readonly Dictionary> PrimitiveTypeConversions = new Dictionary> @@ -40,6 +43,12 @@ namespace Artemis.Core {typeof(string), "string"} }; + /// + /// Determines whether the provided type is of a specified generic type + /// + /// The type to check + /// The generic type to match + /// True if the is generic and of generic type 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) + /// + /// Determines whether the provided type is a struct + /// + /// The type to check + /// if the type is a struct, otherwise + public static bool IsStruct(this Type type) { - return source.IsValueType && !source.IsPrimitive && !source.IsEnum; + return type.IsValueType && !type.IsPrimitive && !type.IsEnum; } + /// + /// Determines whether the provided type is any kind of numeric type + /// + /// The type to check + /// if the type a numeric type, otherwise public static bool TypeIsNumber(this Type type) { return type == typeof(sbyte) @@ -68,6 +87,11 @@ namespace Artemis.Core || type == typeof(decimal); } + /// + /// Determines whether the provided value is any kind of numeric type + /// + /// The value to check + /// if the value is of a numeric type, otherwise public static bool IsNumber(this object value) { return value is sbyte @@ -126,7 +150,7 @@ namespace Artemis.Core /// /// Returns the default value of the given type /// - 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<>)); diff --git a/src/Artemis.Core/JsonConverters/ForgivingIntConverter.cs b/src/Artemis.Core/JsonConverters/ForgivingIntConverter.cs index 77a09cb2b..54edb8ed6 100644 --- a/src/Artemis.Core/JsonConverters/ForgivingIntConverter.cs +++ b/src/Artemis.Core/JsonConverters/ForgivingIntConverter.cs @@ -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(reader); + JValue? jsonValue = serializer.Deserialize(reader); + if (jsonValue == null) + throw new FormatException(); if (jsonValue.Type == JTokenType.Float) return (int) Math.Round(jsonValue.Value()); diff --git a/src/Artemis.Core/MVVM/CorePropertyChanged.cs b/src/Artemis.Core/MVVM/CorePropertyChanged.cs index d4ff0419f..fb1d84497 100644 --- a/src/Artemis.Core/MVVM/CorePropertyChanged.cs +++ b/src/Artemis.Core/MVVM/CorePropertyChanged.cs @@ -13,7 +13,7 @@ namespace Artemis.Core /// /// Occurs when a property value changes. /// - public event PropertyChangedEventHandler PropertyChanged; + public event PropertyChangedEventHandler? PropertyChanged; #endregion diff --git a/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs b/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs index da7a0e1d7..b8edc6780 100644 --- a/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs +++ b/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs @@ -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 /// /// A gradient containing a list of s /// - public class ColorGradient : INotifyPropertyChanged + public class ColorGradient : CorePropertyChanged { /// /// Creates a new instance of the 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 - - /// - public event PropertyChangedEventHandler PropertyChanged; - - [NotifyPropertyChangedInvocator] - internal virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - #endregion } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Colors/ColorGradientStop.cs b/src/Artemis.Core/Models/Profile/Colors/ColorGradientStop.cs index f3009706e..242a883d3 100644 --- a/src/Artemis.Core/Models/Profile/Colors/ColorGradientStop.cs +++ b/src/Artemis.Core/Models/Profile/Colors/ColorGradientStop.cs @@ -1,14 +1,11 @@ -using System.ComponentModel; -using System.Runtime.CompilerServices; -using Artemis.Core.Properties; -using SkiaSharp; +using SkiaSharp; namespace Artemis.Core { /// /// A color with a position, usually contained in a /// - 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); } /// @@ -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 - - /// - public event PropertyChangedEventHandler PropertyChanged; - - [NotifyPropertyChangedInvocator] - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - #endregion } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Conditions/Abstract/BaseConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/BaseConditionOperator.cs index f99c881a7..4214e14de 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Abstract/BaseConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/BaseConditionOperator.cs @@ -25,7 +25,7 @@ namespace Artemis.Core /// Gets the plugin this condition operator belongs to /// Note: Not set until after registering /// - public Plugin Plugin { get; internal set; } + public Plugin? Plugin { get; internal set; } /// /// Gets the left side type of this condition operator @@ -64,9 +64,19 @@ namespace Artemis.Core internal abstract bool InternalEvaluate(object? leftSideValue, object? rightSideValue); } + /// + /// Represents a side of a condition parameter + /// public enum ConditionParameterSide { + /// + /// The left side of a condition parameter + /// Left, + + /// + /// The right side of a condition parameter + /// Right } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs index c42ef85ae..182e4dc30 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs @@ -76,7 +76,7 @@ namespace Artemis.Core /// /// /// - 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; + /// + /// Occurs when a child-condition was added + /// + public event EventHandler? ChildAdded; + /// + /// Occurs when a child-condition was removed + /// + public event EventHandler? ChildRemoved; + + /// + /// Invokers the event + /// protected virtual void OnChildAdded() { ChildAdded?.Invoke(this, EventArgs.Empty); } + /// + /// Invokers the event + /// protected virtual void OnChildRemoved() { ChildRemoved?.Invoke(this, EventArgs.Empty); diff --git a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs index 32bb54423..af81fcaca 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs @@ -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 } } + /// + /// Initializes the left path of this condition predicate + /// protected abstract void InitializeLeftPath(); + + /// + /// Initializes the right path of this condition predicate + /// protected abstract void InitializeRightPath(); #endregion @@ -315,7 +322,7 @@ namespace Artemis.Core } /// - 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); } diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs index c629ef276..fc3b0967b 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs @@ -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; /// /// Creates a new instance of the class @@ -40,10 +40,13 @@ namespace Artemis.Core /// public DataModelPath? EventPath { get; private set; } - public Type? EventArgumentType { get; set; } + /// + /// Gets or sets the type of argument the event provides + /// + public Type? EventArgumentType { get; private set; } internal DataModelConditionEventEntity Entity { get; set; } - + /// 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; - } - /// /// Updates the event the condition is triggered by /// @@ -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 /// @@ -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(); diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEventPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEventPredicate.cs index 4e5f38d02..c6477ba65 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEventPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEventPredicate.cs @@ -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 + /// protected override void InitializeLeftPath() { if (Entity.LeftPath != null) @@ -75,6 +76,7 @@ namespace Artemis.Core : null; } + /// 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; diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGeneralPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGeneralPredicate.cs index 2f29d2f40..e65030a7a 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGeneralPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGeneralPredicate.cs @@ -46,12 +46,14 @@ namespace Artemis.Core #region Initialization + /// protected override void InitializeLeftPath() { if (Entity.LeftPath != null) LeftPath = new DataModelPath(null, Entity.LeftPath); } + /// protected override void InitializeRightPath() { if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null) diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGroup.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGroup.cs index 2b44acb40..851fabb62 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGroup.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGroup.cs @@ -19,7 +19,7 @@ namespace Artemis.Core /// Creates a new instance of the class /// /// - public DataModelConditionGroup(DataModelConditionPart parent) + public DataModelConditionGroup(DataModelConditionPart? parent) { Parent = parent; Entity = new DataModelConditionGroupEntity(); @@ -32,7 +32,7 @@ namespace Artemis.Core /// /// /// - public DataModelConditionGroup(DataModelConditionPart parent, DataModelConditionGroupEntity entity) + public DataModelConditionGroup(DataModelConditionPart? parent, DataModelConditionGroupEntity entity) { Parent = parent; Entity = entity; @@ -124,7 +124,7 @@ namespace Artemis.Core #endregion /// - internal override bool EvaluateObject(object target) + internal override bool EvaluateObject(object? target) { if (_disposed) throw new ObjectDisposedException("DataModelConditionGroup"); diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs index 392e1ba51..a7d523f53 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs @@ -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 { diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs index 32316ec38..b5439c2bf 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs @@ -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 + /// protected override void InitializeLeftPath() { if (Entity.LeftPath != null) @@ -72,6 +73,7 @@ namespace Artemis.Core : null; } + /// 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; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs index 26768b06c..c170b68e5 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs @@ -19,11 +19,14 @@ namespace Artemis.Core Feature = Constants.CorePluginFeature; } + /// + /// Gets the last arguments of this event as an object + /// [DataModelIgnore] - public object? UntypedArguments { get; set; } + public object? UntypedArguments { get; internal set; } /// - /// Creates a new instance of the class + /// Creates a new instance of the class /// public static EventPredicateWrapperDataModel Create(Type type) { diff --git a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs index bfa4396a5..aa512f797 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs @@ -19,6 +19,9 @@ namespace Artemis.Core Feature = Constants.CorePluginFeature; } + /// + /// Gets or sets the value of this list as an object + /// [DataModelIgnore] public object? UntypedValue { get; set; } diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs index f62920e14..86160eb35 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs @@ -6,10 +6,10 @@ namespace Artemis.Core /// public class DataBinding : IDataBinding { - private TProperty _currentValue; + private TProperty _currentValue = default!; + private TProperty _previousValue = default!; private bool _disposed; private TimeSpan _easingProgress; - private TProperty _previousValue; internal DataBinding(DataBindingRegistration dataBindingRegistration) { @@ -34,7 +34,7 @@ namespace Artemis.Core /// /// Gets the data binding registration this data binding is based upon /// - public DataBindingRegistration Registration { get; private set; } + public DataBindingRegistration? Registration { get; private set; } /// /// Gets the layer property this data binding targets @@ -44,12 +44,12 @@ namespace Artemis.Core /// /// Gets the converter used to apply this data binding to the /// - public DataBindingConverter Converter { get; private set; } + public DataBindingConverter? Converter { get; private set; } /// /// Gets the data binding mode /// - public IDataBindingMode DataBindingMode { get; private set; } + public IDataBindingMode? DataBindingMode { get; private set; } /// /// Gets or sets the easing time of the data binding @@ -93,9 +93,9 @@ namespace Artemis.Core /// /// Returns the type of the target property of this data binding /// - 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 registration = LayerProperty.GetDataBindingRegistration(Entity.TargetExpression); + DataBindingRegistration? registration = LayerProperty.GetDataBindingRegistration(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; diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingConverter.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingConverter.cs index c8f2301ac..fe4254c22 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingConverter.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingConverter.cs @@ -13,22 +13,22 @@ namespace Artemis.Core /// /// Gets a dynamically compiled getter pointing to the data bound property /// - public Func GetExpression { get; private set; } + public Func? GetExpression { get; private set; } /// /// Gets a dynamically compiled setter pointing to the data bound property used for value types /// - public Action ValueTypeSetExpression { get; private set; } + public Action? ValueTypeSetExpression { get; private set; } /// /// Gets a dynamically compiled setter pointing to the data bound property used for reference types /// - public Action ReferenceTypeSetExpression { get; private set; } + public Action? ReferenceTypeSetExpression { get; private set; } /// /// Gets the data binding this converter is applied to /// - public DataBinding DataBinding { get; private set; } + public DataBinding? DataBinding { get; private set; } /// /// Gets whether or not this data binding converter supports the method @@ -65,6 +65,8 @@ namespace Artemis.Core /// 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 /// 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 /// public virtual TProperty ConvertFromObject(object? source) { - return (TProperty) Convert.ChangeType(source, typeof(TProperty)); + return (TProperty) Convert.ChangeType(source, typeof(TProperty))!; } /// @@ -96,6 +100,9 @@ namespace Artemis.Core internal void Initialize(DataBinding 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.CurrentValue, assign directly to LayerProperty.CurrentValue - if (DataBinding.Registration.Member == null) + if (DataBinding!.Registration?.Member == null) { CreateSetCurrentValueExpression(); return; } // Ensure the member of LayerProperty.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]); diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingRegistration.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingRegistration.cs index 7a2caa179..00346e68b 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingRegistration.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingRegistration.cs @@ -38,28 +38,28 @@ namespace Artemis.Core /// /// Gets the member the targets - /// null if the is not a member expression + /// if the is not a member expression /// - public MemberInfo Member { get; } + public MemberInfo? Member { get; } /// /// Gets the data binding created using this registration /// - public DataBinding DataBinding { get; internal set; } + public DataBinding? DataBinding { get; internal set; } /// - public IDataBinding GetDataBinding() + public IDataBinding? GetDataBinding() { return DataBinding; } /// - 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; diff --git a/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingRegistration.cs b/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingRegistration.cs index d4a00e574..fb6220951 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingRegistration.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingRegistration.cs @@ -8,12 +8,12 @@ /// /// Returns the data binding applied using this registration /// - public IDataBinding GetDataBinding(); + public IDataBinding? GetDataBinding(); /// /// If found, creates a data binding from storage /// /// - IDataBinding CreateDataBinding(); + IDataBinding? CreateDataBinding(); } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/ConditionalDataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/ConditionalDataBinding.cs index 765e0927c..666e31587 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/ConditionalDataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/ConditionalDataBinding.cs @@ -21,13 +21,13 @@ namespace Artemis.Core Load(); } - internal ConditionalDataBindingEntity Entity { get; } - /// /// Gets a list of conditions applied to this data binding /// public ReadOnlyCollection> Conditions => _conditions.AsReadOnly(); + internal ConditionalDataBindingEntity Entity { get; } + /// public DataBinding DataBinding { get; } @@ -37,9 +37,7 @@ namespace Artemis.Core if (_disposed) throw new ObjectDisposedException("ConditionalDataBinding"); - DataBindingCondition condition = Conditions.FirstOrDefault(c => c.Evaluate()); - if (condition != null) - Console.WriteLine(); + DataBindingCondition? condition = Conditions.FirstOrDefault(c => c.Evaluate()); return condition == null ? baseValue : condition.Value; } @@ -75,7 +73,7 @@ namespace Artemis.Core return condition; } - + /// /// Removes a condition from the conditional data binding's collection and disposes it /// @@ -111,7 +109,7 @@ namespace Artemis.Core } #endregion - + #region Storage /// @@ -138,8 +136,11 @@ namespace Artemis.Core /// /// Occurs when a condition is added or removed /// - public event EventHandler ConditionsUpdated; + public event EventHandler? ConditionsUpdated; + /// + /// Invokes the event + /// protected virtual void OnConditionsUpdated() { ConditionsUpdated?.Invoke(this, EventArgs.Empty); diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/DataBindingCondition.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/DataBindingCondition.cs index bf0f3ff92..9be9256e4 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/DataBindingCondition.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/DataBindingCondition.cs @@ -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(Entity.Value); + Value = (Entity.Value == null ? default : JsonConvert.DeserializeObject(Entity.Value))!; Order = Entity.Order; } diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/BaseDataBindingModifierType.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/BaseDataBindingModifierType.cs index b3f2ec115..2d85efb96 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/BaseDataBindingModifierType.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/BaseDataBindingModifierType.cs @@ -15,7 +15,7 @@ namespace Artemis.Core /// Gets the plugin this data binding modifier belongs to /// Note: Not set until after registering /// - public Plugin Plugin { get; internal set; } + public Plugin? Plugin { get; internal set; } /// /// Gets the value type of this modifier type @@ -35,17 +35,17 @@ namespace Artemis.Core /// /// Gets or sets the icon of this modifier /// - public abstract string Icon { get; } + public abstract string? Icon { get; } /// /// Gets the description of this modifier /// - public virtual string Description => null; + public virtual string? Description => null; /// /// Gets the category of this modifier /// - public virtual string Category => null; + public virtual string? Category => null; /// /// Returns whether the given type is supported by the modifier @@ -69,14 +69,26 @@ namespace Artemis.Core /// /// /// The current value before modification, type should match - /// The parameter to use for the modification, type should match + /// + /// The parameter to use for the modification, type should match + /// /// The modified value, with a type of internal abstract object? InternalApply(object? currentValue, object? parameterValue); } + /// + /// Represents a part of a modifier type + /// public enum ModifierTypePart { + /// + /// The value part of a modifier, backed by + /// Value, + + /// + /// The parameter part of a modifier, backed by + /// Parameter } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs index 02235faa2..b0b10c0e5 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs @@ -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 /// /// The static value to use as a parameter - 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); diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs index 9907f1175..03dada505 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs @@ -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 /// public event EventHandler? ModifiersUpdated; + /// + /// Invokes the event + /// protected virtual void OnModifiersUpdated() { ModifiersUpdated?.Invoke(this, EventArgs.Empty); diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs index f7ce3f942..a784716ec 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs @@ -318,18 +318,24 @@ namespace Artemis.Core /// /// Occurs whenever the path becomes invalid /// - public event EventHandler PathInvalidated; + public event EventHandler? PathInvalidated; /// /// Occurs whenever the path becomes valid /// - public event EventHandler PathValidated; + public event EventHandler? PathValidated; + /// + /// Invokes the event + /// protected virtual void OnPathValidated() { PathValidated?.Invoke(this, EventArgs.Empty); } + /// + /// Invokes the event + /// protected virtual void OnPathInvalidated() { PathInvalidated?.Invoke(this, EventArgs.Empty); diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs index fb7b191c9..063a18386 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs @@ -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) ); diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs index 94a3909f8..f764ca544 100644 --- a/src/Artemis.Core/Models/Profile/Folder.cs +++ b/src/Artemis.Core/Models/Profile/Folder.cs @@ -30,8 +30,8 @@ namespace Artemis.Core Name = name; Enabled = true; - _layerEffects = new List(); - _expandedPropertyGroups = new List(); + LayerEffectsList = new List(); + ExpandedPropertyGroups = new List(); Parent.AddChild(this); } @@ -47,8 +47,8 @@ namespace Artemis.Core Enabled = folderEntity.Enabled; Order = folderEntity.Order; - _layerEffects = new List(); - _expandedPropertyGroups = new List(); + LayerEffectsList = new List(); + ExpandedPropertyGroups = new List(); Load(); } @@ -58,11 +58,6 @@ namespace Artemis.Core /// public bool IsRootFolder => Parent == Profile; - /// - /// Gets the longest timeline of all this folders children - /// - 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; } + /// public override void Update(double deltaTime) { if (Disposed) @@ -129,6 +125,9 @@ namespace Artemis.Core /// The newly created copy 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(JsonConvert.SerializeObject(FolderEntity, settings), settings)!; entityCopy.Id = Guid.NewGuid(); @@ -139,12 +138,13 @@ namespace Artemis.Core return new Folder(Profile, Parent, entityCopy); } + /// 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 + /// public override void Render(SKCanvas canvas) { if (Disposed) @@ -278,9 +230,62 @@ namespace Artemis.Core #endregion + /// + 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; + /// + /// Occurs when a property affecting the rendering properties of this folder has been updated + /// + public event EventHandler? RenderPropertiesUpdated; private void OnRenderPropertiesUpdated() { diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index 2313aae6b..89c91cf3e 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -17,10 +17,10 @@ namespace Artemis.Core public sealed class Layer : RenderProfileElement { private LayerGeneralProperties _general; - private BaseLayerBrush _layerBrush; - private LayerShape _layerShape; - private List _leds; + private BaseLayerBrush? _layerBrush; private LayerTransformProperties _transform; + private LayerShape? _layerShape; + private List _leds; /// /// Creates a new instance of the 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(); + LayerEffectsList = new List(); _leds = new List(); - _expandedPropertyGroups = new List(); + ExpandedPropertyGroups = new List(); Initialize(); Parent.AddChild(this); @@ -55,12 +55,12 @@ namespace Artemis.Core Profile = profile; Parent = parent; - General = new LayerGeneralProperties(); - Transform = new LayerTransformProperties(); - - _layerEffects = new List(); + _general = new LayerGeneralProperties(); + _transform = new LayerTransformProperties(); + + LayerEffectsList = new List(); _leds = new List(); - _expandedPropertyGroups = new List(); + ExpandedPropertyGroups = new List(); Load(); Initialize(); @@ -74,7 +74,7 @@ namespace Artemis.Core /// /// Defines the shape that is rendered by the . /// - public LayerShape LayerShape + public LayerShape? LayerShape { get => _layerShape; set @@ -85,24 +85,30 @@ namespace Artemis.Core } } + /// + /// Gets the general properties of the layer + /// [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); } + /// + /// Gets the transform properties of the layer + /// [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); } /// /// The brush that will fill the . /// - 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; - + /// /// Creates a deep copy of the layer /// /// The newly created copy 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(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 /// + /// Whether translation should be included + /// Whether the scale should be included + /// Whether the rotation should be included /// The transformation matrix containing the current transformation settings 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 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; + /// + /// Occurs when a property affecting the rendering properties of this layer has been updated + /// + public event EventHandler? RenderPropertiesUpdated; + + /// + /// Occurs when the layer brush of this layer has been updated + /// + public event EventHandler? LayerBrushUpdated; private void OnRenderPropertiesUpdated() { @@ -683,15 +717,35 @@ namespace Artemis.Core #endregion } + /// + /// Represents a type of layer shape + /// public enum LayerShapeType { + /// + /// A circular layer shape + /// Ellipse, + + /// + /// A rectangular layer shape + /// Rectangle } + /// + /// Represents a layer transform mode + /// public enum LayerTransformMode { + /// + /// Normal transformation + /// Normal, + + /// + /// Transforms only a clip + /// Clip } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerBrushReference.cs b/src/Artemis.Core/Models/Profile/LayerBrushReference.cs index e9cf6d946..d36617278 100644 --- a/src/Artemis.Core/Models/Profile/LayerBrushReference.cs +++ b/src/Artemis.Core/Models/Profile/LayerBrushReference.cs @@ -7,10 +7,17 @@ namespace Artemis.Core /// public class LayerBrushReference { + /// + /// Creates a new instance of the class + /// public LayerBrushReference() { } + /// + /// Creates a new instance of the class + /// + /// The descriptor to point the new reference at public LayerBrushReference(LayerBrushDescriptor descriptor) { LayerBrushProviderId = descriptor.Provider.Id; @@ -20,11 +27,11 @@ namespace Artemis.Core /// /// The ID of the layer brush provided the brush was provided by /// - public string LayerBrushProviderId { get; set; } + public string? LayerBrushProviderId { get; set; } /// /// The full type name of the brush descriptor /// - public string BrushType { get; set; } + public string? BrushType { get; set; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerGeneralProperties.cs b/src/Artemis.Core/Models/Profile/LayerGeneralProperties.cs index 6f55911d7..b434ccb2f 100644 --- a/src/Artemis.Core/Models/Profile/LayerGeneralProperties.cs +++ b/src/Artemis.Core/Models/Profile/LayerGeneralProperties.cs @@ -1,31 +1,51 @@ using SkiaSharp; +#pragma warning disable 8618 + namespace Artemis.Core { + /// + /// Represents the general properties of a layer + /// public class LayerGeneralProperties : LayerPropertyGroup { + /// + /// The type of shape to draw in this layer + /// [PropertyDescription(Name = "Shape type", Description = "The type of shape to draw in this layer")] public EnumLayerProperty ShapeType { get; set; } + /// + /// How to blend this layer into the resulting image + /// [PropertyDescription(Name = "Blend mode", Description = "How to blend this layer into the resulting image")] public EnumLayerProperty BlendMode { get; set; } + /// + /// How the transformation properties are applied to the layer + /// [PropertyDescription(Name = "Transform mode", Description = "How the transformation properties are applied to the layer")] public EnumLayerProperty TransformMode { get; set; } + /// + /// The type of brush to use for this layer + /// [PropertyDescription(Name = "Brush type", Description = "The type of brush to use for this layer")] public LayerBrushReferenceLayerProperty BrushReference { get; set; } + /// protected override void PopulateDefaults() { ShapeType.DefaultValue = LayerShapeType.Rectangle; BlendMode.DefaultValue = SKBlendMode.SrcOver; } + /// protected override void EnableProperties() { } + /// protected override void DisableProperties() { } diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyDescriptionAttribute.cs b/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyDescriptionAttribute.cs index 733c95683..e4b63a567 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyDescriptionAttribute.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyDescriptionAttribute.cs @@ -2,27 +2,30 @@ namespace Artemis.Core { + /// + /// Represents a description attribute used to decorate layer properties + /// public class PropertyDescriptionAttribute : Attribute { /// /// The user-friendly name for this property, shown in the UI /// - public string Name { get; set; } + public string? Name { get; set; } /// /// The user-friendly description for this property, shown in the UI /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Input prefix to show before input elements in the UI /// - public string InputPrefix { get; set; } + public string? InputPrefix { get; set; } /// /// Input affix to show behind input elements in the UI /// - public string InputAffix { get; set; } + public string? InputAffix { get; set; } /// /// The input drag step size, used in the UI @@ -32,12 +35,12 @@ namespace Artemis.Core /// /// Minimum input value, only enforced in the UI /// - public object MinInputValue { get; set; } + public object? MinInputValue { get; set; } /// /// Maximum input value, only enforced in the UI /// - public object MaxInputValue { get; set; } + public object? MaxInputValue { get; set; } /// /// Whether or not keyframes are always disabled diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyGroupDescriptionAttribute.cs b/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyGroupDescriptionAttribute.cs index 572b5508a..98cdb74db 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyGroupDescriptionAttribute.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyGroupDescriptionAttribute.cs @@ -2,16 +2,19 @@ namespace Artemis.Core { + /// + /// Represents a description attribute used to decorate layer property groups + /// public class PropertyGroupDescriptionAttribute : Attribute { /// /// The user-friendly name for this property, shown in the UI. /// - public string Name { get; set; } + public string? Name { get; set; } /// /// The user-friendly description for this property, shown in the UI. /// - public string Description { get; set; } + public string? Description { get; set; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs index 39a18a503..16b34b8c2 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs @@ -25,9 +25,22 @@ namespace Artemis.Core /// protected LayerProperty() { + // Cant define generic types as nullable ¯\_(ツ)_/¯ + CurrentValue = default!; + DefaultValue = default!; + + _baseValue = default!; _keyframes = new List>(); } + /// + /// Returns the type of the property + /// + public Type GetPropertyType() + { + return typeof(T); + } + /// public PropertyDescriptionAttribute PropertyDescription { get; internal set; } @@ -57,14 +70,6 @@ namespace Artemis.Core dataBinding.Dispose(); } - /// - /// Returns the type of the property - /// - 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 currentKeyframe = Keyframes.FirstOrDefault(k => k.Position == time.Value); + LayerPropertyKeyframe? currentKeyframe = Keyframes.FirstOrDefault(k => k.Position == time.Value); // Create a new keyframe if none found if (currentKeyframe == null) AddKeyframe(new LayerPropertyKeyframe(value, time.Value, Easings.Functions.Linear, this)); @@ -222,12 +229,12 @@ namespace Artemis.Core /// /// Gets the current keyframe in the timeline according to the current progress /// - public LayerPropertyKeyframe CurrentKeyframe { get; protected set; } + public LayerPropertyKeyframe? CurrentKeyframe { get; protected set; } /// /// Gets the next keyframe in the timeline according to the current progress /// - public LayerPropertyKeyframe NextKeyframe { get; protected set; } + public LayerPropertyKeyframe? NextKeyframe { get; protected set; } /// /// Adds a keyframe to the layer property @@ -249,26 +256,6 @@ namespace Artemis.Core OnKeyframeAdded(); } - /// - /// Removes a keyframe from the layer property - /// - /// The keyframe to remove - public LayerPropertyKeyframe CopyKeyframe(LayerPropertyKeyframe keyframe) - { - if (_disposed) - throw new ObjectDisposedException("LayerProperty"); - - LayerPropertyKeyframe newKeyframe = new LayerPropertyKeyframe( - keyframe.Value, - keyframe.Position, - keyframe.EasingFunction, - keyframe.LayerProperty - ); - AddKeyframe(newKeyframe); - - return newKeyframe; - } - /// /// Removes a keyframe from the layer property /// @@ -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 _dataBindingRegistrations = new List(); + internal readonly List _dataBindings = new List(); + // ReSharper restore InconsistentNaming /// /// 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 /// Note: The expression must exactly match the one used to register the data binding /// - public DataBindingRegistration GetDataBindingRegistration(Expression> propertyExpression) + public DataBindingRegistration? GetDataBindingRegistration(Expression> propertyExpression) { return GetDataBindingRegistration(propertyExpression.ToString()); } - public DataBindingRegistration GetDataBindingRegistration(string expression) + internal DataBindingRegistration? GetDataBindingRegistration(string expression) { if (_disposed) throw new ObjectDisposedException("LayerProperty"); - IDataBindingRegistration match = _dataBindingRegistrations.FirstOrDefault(r => r is DataBindingRegistration registration && - registration.PropertyExpression.ToString() == expression); - - return (DataBindingRegistration) match; + IDataBindingRegistration? match = _dataBindingRegistrations.FirstOrDefault(r => r is DataBindingRegistration registration && + registration.PropertyExpression.ToString() == expression); + return (DataBindingRegistration?) match; } + /// + /// Gets a list containing all data binding registrations of this layer property + /// + /// A list containing all data binding registrations of this layer property public List GetAllDataBindingRegistrations() { return _dataBindingRegistrations; } + /// + /// Registers a data binding property so that is available to the data binding system + /// + /// The type of the layer property + /// The expression pointing to the value to register + /// The converter to use while applying the data binding public void RegisterDataBindingProperty(Expression> propertyExpression, DataBindingConverter 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(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(dataBinding.LayerProperty)); } @@ -471,17 +479,15 @@ namespace Artemis.Core if (!IsLoadedFromStorage) ApplyDefaultValue(); else - { try { if (Entity.Value != null) BaseValue = JsonConvert.DeserializeObject(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(JsonConvert.DeserializeObject(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); } } /// - /// Saves the property to the underlying property entity that was configured when calling - /// + /// Saves the property to the underlying property entity /// public void Save() { @@ -542,79 +547,103 @@ namespace Artemis.Core /// /// Occurs once every frame when the layer property is updated /// - public event EventHandler> Updated; + public event EventHandler>? Updated; /// /// Occurs when the current value of the layer property was updated by some form of input /// - public event EventHandler> CurrentValueSet; + public event EventHandler>? CurrentValueSet; /// /// Occurs when the value of the layer property was updated /// - public event EventHandler> VisibilityChanged; + public event EventHandler>? VisibilityChanged; /// /// Occurs when keyframes are enabled/disabled /// - public event EventHandler> KeyframesToggled; + public event EventHandler>? KeyframesToggled; /// /// Occurs when a new keyframe was added to the layer property /// - public event EventHandler> KeyframeAdded; + public event EventHandler>? KeyframeAdded; /// /// Occurs when a keyframe was removed from the layer property /// - public event EventHandler> KeyframeRemoved; + public event EventHandler>? KeyframeRemoved; /// /// Occurs when a data binding has been enabled /// - public event EventHandler> DataBindingEnabled; + public event EventHandler>? DataBindingEnabled; /// /// Occurs when a data binding has been disabled /// - public event EventHandler> DataBindingDisabled; + public event EventHandler>? DataBindingDisabled; + /// + /// Invokes the event + /// protected virtual void OnUpdated() { Updated?.Invoke(this, new LayerPropertyEventArgs(this)); } + /// + /// Invokes the event + /// protected virtual void OnCurrentValueSet() { CurrentValueSet?.Invoke(this, new LayerPropertyEventArgs(this)); LayerPropertyGroup.OnLayerPropertyOnCurrentValueSet(new LayerPropertyEventArgs(this)); } + /// + /// Invokes the event + /// protected virtual void OnVisibilityChanged() { VisibilityChanged?.Invoke(this, new LayerPropertyEventArgs(this)); } + /// + /// Invokes the event + /// protected virtual void OnKeyframesToggled() { KeyframesToggled?.Invoke(this, new LayerPropertyEventArgs(this)); } + /// + /// Invokes the event + /// protected virtual void OnKeyframeAdded() { KeyframeAdded?.Invoke(this, new LayerPropertyEventArgs(this)); } + /// + /// Invokes the event + /// protected virtual void OnKeyframeRemoved() { KeyframeRemoved?.Invoke(this, new LayerPropertyEventArgs(this)); } + /// + /// Invokes the event + /// protected virtual void OnDataBindingEnabled(LayerPropertyEventArgs e) { DataBindingEnabled?.Invoke(this, e); } + /// + /// Invokes the event + /// protected virtual void OnDataBindingDisabled(LayerPropertyEventArgs e) { DataBindingDisabled?.Invoke(this, e); diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs index 3afe363bd..e58dd5635 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs @@ -21,9 +21,9 @@ namespace Artemis.Core public LayerPropertyKeyframe(T value, TimeSpan position, Easings.Functions easingFunction, LayerProperty layerProperty) { _position = position; + _layerProperty = layerProperty; + _value = value; - Value = value; - LayerProperty = layerProperty; EasingFunction = easingFunction; } diff --git a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs index b3fbfe5ff..5369ebaf6 100644 --- a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs +++ b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs @@ -11,6 +11,13 @@ using Humanizer; namespace Artemis.Core { + /// + /// Represents a property group on a layer + /// + /// Note: You cannot initialize property groups yourself. If properly placed and annotated, the Artemis core will + /// initialize these for you. + /// + /// public abstract class LayerPropertyGroup : IDisposable { private readonly List _layerProperties; @@ -18,6 +25,9 @@ namespace Artemis.Core private bool _disposed; private bool _isHidden; + /// + /// A base constructor for a + /// protected LayerPropertyGroup() { _layerProperties = new List(); @@ -28,7 +38,7 @@ namespace Artemis.Core /// Gets the description of this group /// public PropertyGroupDescriptionAttribute GroupDescription { get; internal set; } - + /// /// Gets the plugin feature this group is associated with /// @@ -87,22 +97,6 @@ namespace Artemis.Core /// public ReadOnlyCollection LayerPropertyGroups => _layerPropertyGroups.AsReadOnly(); - #region IDisposable - - /// - public void Dispose() - { - _disposed = true; - DisableProperties(); - - foreach (ILayerProperty layerProperty in _layerProperties) - layerProperty.Dispose(); - foreach (LayerPropertyGroup layerPropertyGroup in _layerPropertyGroups) - layerPropertyGroup.Dispose(); - } - - #endregion - /// /// Recursively gets all layer properties on this group and any subgroups /// @@ -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 + + /// + public void Dispose() + { + _disposed = true; + DisableProperties(); + + foreach (ILayerProperty layerProperty in _layerProperties) + layerProperty.Dispose(); + foreach (LayerPropertyGroup layerPropertyGroup in _layerPropertyGroups) + layerPropertyGroup.Dispose(); + } + + #endregion + #region Events /// diff --git a/src/Artemis.Core/Models/Profile/LayerTransformProperties.cs b/src/Artemis.Core/Models/Profile/LayerTransformProperties.cs index 7c9d8c2ff..9a78aba1c 100644 --- a/src/Artemis.Core/Models/Profile/LayerTransformProperties.cs +++ b/src/Artemis.Core/Models/Profile/LayerTransformProperties.cs @@ -1,34 +1,57 @@ using SkiaSharp; +#pragma warning disable 8618 + namespace Artemis.Core { + /// + /// Represents the transform properties of a layer + /// public class LayerTransformProperties : LayerPropertyGroup { + /// + /// The point at which the shape is attached to its position + /// [PropertyDescription(Description = "The point at which the shape is attached to its position", InputStepSize = 0.001f)] public SKPointLayerProperty AnchorPoint { get; set; } + /// + /// The position of the shape + /// [PropertyDescription(Description = "The position of the shape", InputStepSize = 0.001f)] public SKPointLayerProperty Position { get; set; } + /// + /// The scale of the shape + /// [PropertyDescription(Description = "The scale of the shape", InputAffix = "%", MinInputValue = 0f)] public SKSizeLayerProperty Scale { get; set; } + /// + /// The rotation of the shape in degree + /// [PropertyDescription(Description = "The rotation of the shape in degrees", InputAffix = "°")] public FloatLayerProperty Rotation { get; set; } + /// + /// The opacity of the shape + /// [PropertyDescription(Description = "The opacity of the shape", InputAffix = "%", MinInputValue = 0f, MaxInputValue = 100f)] public FloatLayerProperty Opacity { get; set; } + /// protected override void PopulateDefaults() { Scale.DefaultValue = new SKSize(100, 100); Opacity.DefaultValue = 100; } + /// protected override void EnableProperties() { } + /// protected override void DisableProperties() { } diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs index 40d61fd06..177d77a50 100644 --- a/src/Artemis.Core/Models/Profile/Profile.cs +++ b/src/Artemis.Core/Models/Profile/Profile.cs @@ -7,6 +7,9 @@ using SkiaSharp; namespace Artemis.Core { + /// + /// Represents a profile containing folders and layers + /// public sealed class Profile : ProfileElement { private bool _isActivated; @@ -39,8 +42,14 @@ namespace Artemis.Core Load(); } + /// + /// Gets the module backing this profile + /// public ProfileModule Module { get; } + /// + /// Gets a boolean indicating whether this profile is activated + /// public bool IsActivated { get => _isActivated; @@ -52,6 +61,7 @@ namespace Artemis.Core internal Stack UndoStack { get; set; } internal Stack RedoStack { get; set; } + /// public override void Update(double deltaTime) { lock (this) @@ -66,6 +76,7 @@ namespace Artemis.Core } } + /// public override void Render(SKCanvas canvas) { lock (this) @@ -87,6 +98,11 @@ namespace Artemis.Core child.Reset(); } + /// + /// Retrieves the root folder of this profile + /// + /// The root folder of the profile + /// public Folder GetRootFolder() { if (Disposed) @@ -95,6 +111,28 @@ namespace Artemis.Core return (Folder) Children.Single(); } + /// + 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 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 /// /// Occurs when the profile has been activated. /// - public event EventHandler Activated; + public event EventHandler? Activated; /// /// Occurs when the profile is being deactivated. /// - public event EventHandler Deactivated; + public event EventHandler? Deactivated; private void OnActivated() { diff --git a/src/Artemis.Core/Models/Profile/ProfileDescriptor.cs b/src/Artemis.Core/Models/Profile/ProfileDescriptor.cs index 7c91c4f6a..ee5c67b87 100644 --- a/src/Artemis.Core/Models/Profile/ProfileDescriptor.cs +++ b/src/Artemis.Core/Models/Profile/ProfileDescriptor.cs @@ -4,6 +4,9 @@ using Artemis.Storage.Entities.Profile; namespace Artemis.Core { + /// + /// Represents a descriptor that describes a profile + /// public class ProfileDescriptor { internal ProfileDescriptor(ProfileModule profileModule, ProfileEntity profileEntity) @@ -15,10 +18,24 @@ namespace Artemis.Core IsLastActiveProfile = profileEntity.IsActive; } - public bool IsLastActiveProfile { get; set; } + /// + /// Gets a boolean indicating whether this was the last active profile + /// + public bool IsLastActiveProfile { get; } + /// + /// Gets the unique ID of the profile by which it can be loaded from storage + /// public Guid Id { get; } + + /// + /// Gets the module backing the profile + /// public ProfileModule ProfileModule { get; } + + /// + /// Gets the name of the profile + /// public string Name { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/ProfileElement.cs b/src/Artemis.Core/Models/Profile/ProfileElement.cs index e55851f38..29183378c 100644 --- a/src/Artemis.Core/Models/Profile/ProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/ProfileElement.cs @@ -6,18 +6,22 @@ using SkiaSharp; namespace Artemis.Core { + /// + /// Represents an element of a + /// 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 ChildrenList; - protected bool Disposed; - protected ProfileElement() + internal List ChildrenList; + internal bool Disposed; + + internal ProfileElement() { ChildrenList = new List(); } @@ -43,7 +47,7 @@ namespace Artemis.Core /// /// Gets the parent of this element /// - public ProfileElement Parent + public ProfileElement? Parent { get => _parent; internal set => SetAndNotify(ref _parent, value); @@ -233,6 +237,9 @@ namespace Artemis.Core GC.SuppressFinalize(this); } + /// + /// Disposes the profile element + /// 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; + /// + /// Occurs when a child was added to the list + /// + public event EventHandler? ChildAdded; + /// + /// Occurs when a child was removed from the list + /// + public event EventHandler? ChildRemoved; + + /// + /// Invokes the event + /// protected virtual void OnChildAdded() { ChildAdded?.Invoke(this, EventArgs.Empty); } + /// + /// Invokes the event + /// protected virtual void OnChildRemoved() { ChildRemoved?.Invoke(this, EventArgs.Empty); diff --git a/src/Artemis.Core/Models/Profile/PropertiesProfileElement.cs b/src/Artemis.Core/Models/Profile/PropertiesProfileElement.cs deleted file mode 100644 index 0759ed0e5..000000000 --- a/src/Artemis.Core/Models/Profile/PropertiesProfileElement.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Artemis.Core -{ - public abstract class PropertiesProfileElement : ProfileElement - { - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs index 4a4343121..2365c9d9a 100644 --- a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs @@ -11,9 +11,12 @@ using SkiaSharp; namespace Artemis.Core { + /// + /// Represents an element of a that has advanced rendering capabilities + /// 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; } + /// + /// Creates a list of all layer properties present on this render element + /// + /// A list of all layer properties present on this render element public abstract List GetAllLayerProperties(); + #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 + internal void LoadRenderElement() { DisplayCondition = RenderElementEntity.DisplayCondition != null @@ -73,7 +96,8 @@ namespace Artemis.Core public Timeline Timeline { get; private set; } /// - /// Updates the according to the provided and current display condition status + /// Updates the according to the provided and current display + /// condition status /// 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; } /// /// Gets the parent of this element /// - 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. /// - public SKPath Path + public SKPath? Path { get => _path; protected set @@ -150,20 +159,30 @@ namespace Artemis.Core #region Property group expansion - protected List _expandedPropertyGroups; + internal List ExpandedPropertyGroups; private SKRect _bounds; + /// + /// Determines whether the provided property group is expanded + /// + /// The property group to check + /// A boolean indicating whether the provided property group is expanded public bool IsPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup) { - return _expandedPropertyGroups.Contains(layerPropertyGroup.Path); + return ExpandedPropertyGroups.Contains(layerPropertyGroup.Path); } + /// + /// Expands or collapses the provided property group + /// + /// The group to expand or collapse + /// Whether to expand or collapse the property group 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 _layerEffects; + internal List LayerEffectsList; /// /// Gets a read-only collection of the layer effects on this entity /// - public ReadOnlyCollection LayerEffects => _layerEffects.AsReadOnly(); + public ReadOnlyCollection LayerEffects => LayerEffectsList.AsReadOnly(); /// /// Adds a the layer effect described inthe provided @@ -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 pluginEffects = _layerEffects.Where(ef => ef.Descriptor.Provider != null && - ef.ProviderId == e.Registration.PluginFeature.Id).ToList(); + List 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 } /// - /// Evaluates the display conditions on this element and applies any required changes to the + /// Evaluates the display conditions on this element and applies any required changes to the /// 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; + /// + /// Occurs when a layer effect has been added or removed to this render element + /// + public event EventHandler? LayerEffectsUpdated; internal void OnLayerEffectsUpdated() { diff --git a/src/Artemis.Core/Models/Profile/Renderer.cs b/src/Artemis.Core/Models/Profile/Renderer.cs index c16d69ea8..03b4e1fb7 100644 --- a/src/Artemis.Core/Models/Profile/Renderer.cs +++ b/src/Artemis.Core/Models/Profile/Renderer.cs @@ -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) diff --git a/src/Artemis.Core/Models/Profile/Timeline.cs b/src/Artemis.Core/Models/Profile/Timeline.cs index f50e7d922..f4bfc52bd 100644 --- a/src/Artemis.Core/Models/Profile/Timeline.cs +++ b/src/Artemis.Core/Models/Profile/Timeline.cs @@ -429,6 +429,7 @@ namespace Artemis.Core #endregion + /// public override string ToString() { return $"Progress: {Position}/{Length} - delta: {Delta}"; diff --git a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs index adf4e6d20..f99b35771 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs @@ -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 { + /// + /// Represents an RGB device usable by Artemis, provided by a + /// public class ArtemisDevice : CorePropertyChanged { private ReadOnlyCollection _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(); } + /// + /// Gets the rectangle covering the device, sized to match the render scale + /// public SKRect RenderRectangle { get => _renderRectangle; private set => SetAndNotify(ref _renderRectangle, value); } + /// + /// Gets the path surrounding the device, sized to match the render scale + /// public SKPath RenderPath { get => _renderPath; private set => SetAndNotify(ref _renderPath, value); } + /// + /// Gets the RGB.NET device backing this Artemis device + /// public IRGBDevice RgbDevice { get; } - public PluginFeature PluginFeature { get; } - public ArtemisSurface Surface { get; } - public DeviceEntity DeviceEntity { get; } + /// + /// Gets the device provider that provided this device + /// + public DeviceProvider DeviceProvider { get; } + + /// + /// Gets the surface containing this device + /// + public ArtemisSurface Surface { get; } + + /// + /// Gets a read only collection containing the LEDs of this device + /// public ReadOnlyCollection Leds { get => _leds; - set => SetAndNotify(ref _leds, value); + private set => SetAndNotify(ref _leds, value); } + /// + /// Gets or sets the X-position of the device + /// public double X { get => DeviceEntity.X; @@ -71,6 +97,9 @@ namespace Artemis.Core } } + /// + /// Gets or sets the Y-position of the device + /// public double Y { get => DeviceEntity.Y; @@ -81,6 +110,9 @@ namespace Artemis.Core } } + /// + /// Gets or sets the rotation of the device + /// public double Rotation { get => DeviceEntity.Rotation; @@ -91,6 +123,9 @@ namespace Artemis.Core } } + /// + /// Gets or sets the scale of the device + /// public double Scale { get => DeviceEntity.Scale; @@ -101,6 +136,9 @@ namespace Artemis.Core } } + /// + /// Gets or sets the Z-index of the device + /// public int ZIndex { get => DeviceEntity.ZIndex; @@ -111,13 +149,22 @@ namespace Artemis.Core } } + internal DeviceEntity DeviceEntity { get; } + + /// public override string ToString() { return $"[{RgbDevice.DeviceInfo.DeviceType}] {RgbDevice.DeviceInfo.DeviceName} - {X}.{Y}.{ZIndex}"; } - public event EventHandler DeviceUpdated; + /// + /// Occurs when the underlying RGB.NET device was updated + /// + public event EventHandler? DeviceUpdated; + /// + /// Invokes the event + /// protected virtual void OnDeviceUpdated() { DeviceUpdated?.Invoke(this, EventArgs.Empty); diff --git a/src/Artemis.Core/Models/Surface/ArtemisLed.cs b/src/Artemis.Core/Models/Surface/ArtemisLed.cs index 0c55c356f..4cc6d003b 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisLed.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisLed.cs @@ -3,35 +3,51 @@ using SkiaSharp; namespace Artemis.Core { + /// + /// Represents an RGB LED contained in an + /// 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); + /// + /// Gets the RGB.NET LED backing this Artemis LED + /// public Led RgbLed { get; } + + /// + /// Gets the device that contains this LED + /// public ArtemisDevice Device { get; } + /// + /// Gets the rectangle covering the LED, sized to match the render scale and positioned relative to the + /// + /// public SKRect RenderRectangle { get => _renderRectangle; private set => SetAndNotify(ref _renderRectangle, value); } + /// + /// Gets the rectangle covering the LED, sized to match the render scale + /// 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(), diff --git a/src/Artemis.Core/Models/Surface/ArtemisSurface.cs b/src/Artemis.Core/Models/Surface/ArtemisSurface.cs index f79040289..9a4fabcc1 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisSurface.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisSurface.cs @@ -6,6 +6,9 @@ using RGB.NET.Core; namespace Artemis.Core { + /// + /// Represents a surface of a specific scale, containing all the available s + /// public class ArtemisSurface : CorePropertyChanged { private List _devices; @@ -17,14 +20,14 @@ namespace Artemis.Core { SurfaceEntity = new SurfaceEntity {DeviceEntities = new List()}; 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(); + _devices = new List(); 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(); + _devices = new List(); } + /// + /// Gets the RGB.NET surface backing this Artemis surface + /// public RGBSurface RgbSurface { get; } + /// + /// Gets the scale at which this surface is rendered + /// public double Scale { get => _scale; private set => SetAndNotify(ref _scale, value); } + /// + /// Gets the name of the surface + /// public string Name { get => _name; set => SetAndNotify(ref _name, value); } + /// + /// Gets a boolean indicating whether this surface is the currently active surface + /// public bool IsActive { get => _isActive; internal set => SetAndNotify(ref _isActive, value); } + /// + /// Gets a list of devices this surface contains + /// public List Devices { get => _devices; @@ -72,6 +90,10 @@ namespace Artemis.Core internal SurfaceEntity SurfaceEntity { get; set; } internal Guid EntityId { get; set; } + /// + /// Updates the scale of the surface + /// + /// 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 ScaleChanged; + /// + /// Occurs when the scale of the surface is changed + /// + public event EventHandler? ScaleChanged; + /// + /// Invokes the event + /// protected virtual void OnScaleChanged() { ScaleChanged?.Invoke(this, EventArgs.Empty); diff --git a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs index dfbd52efd..fd57053cb 100644 --- a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs +++ b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs @@ -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 { + /// + /// Represents a data model that contains information on a game/application etc. + /// public abstract class DataModel { private readonly Dictionary _dynamicDataModels = new Dictionary(); @@ -154,11 +156,17 @@ namespace Artemis.Core.DataModelExpansions /// public event EventHandler? DynamicDataModelRemoved; + /// + /// Invokes the event + /// protected virtual void OnDynamicDataModelAdded(DynamicDataModelEventArgs e) { DynamicDataModelAdded?.Invoke(this, e); } + /// + /// Invokes the event + /// protected virtual void OnDynamicDataModelRemoved(DynamicDataModelEventArgs e) { DynamicDataModelRemoved?.Invoke(this, e); diff --git a/src/Artemis.Core/Plugins/IPluginConfigurationDialog.cs b/src/Artemis.Core/Plugins/IPluginConfigurationDialog.cs index c76d777ca..27736b149 100644 --- a/src/Artemis.Core/Plugins/IPluginConfigurationDialog.cs +++ b/src/Artemis.Core/Plugins/IPluginConfigurationDialog.cs @@ -1,7 +1,9 @@ namespace Artemis.Core { + /// + /// Represents a configuration dialog for a + /// public interface IPluginConfigurationDialog { - } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs index e7089c4ba..fd0661a94 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs @@ -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 /// /// Gets the descriptor of this brush /// - public LayerBrushDescriptor Descriptor + public LayerBrushDescriptor? Descriptor { get => _descriptor; internal set => SetAndNotify(ref _descriptor, value); @@ -35,7 +35,7 @@ namespace Artemis.Core.LayerBrushes /// /// Gets or sets a configuration dialog complementing the regular properties /// - public ILayerBrushConfigurationDialog ConfigurationDialog + public ILayerBrushConfigurationDialog? ConfigurationDialog { get => _configurationDialog; protected set => SetAndNotify(ref _configurationDialog, value); @@ -53,12 +53,12 @@ namespace Artemis.Core.LayerBrushes /// /// Gets the ID of the that provided this effect /// - public string ProviderId => Descriptor?.Provider?.Id; + public string? ProviderId => Descriptor?.Provider.Id; /// /// Gets a reference to the layer property group without knowing it's type /// - public virtual LayerPropertyGroup BaseProperties => null; + public virtual LayerPropertyGroup? BaseProperties => null; /// /// 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); diff --git a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs index 4b1da7753..b8673a261 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs @@ -46,7 +46,7 @@ namespace Artemis.Core.LayerBrushes /// /// Determines whether the provided references to a brush provided by this descriptor /// - public bool MatchesLayerBrushReference(LayerBrushReference reference) + public bool MatchesLayerBrushReference(LayerBrushReference? reference) { if (reference == null) return false; diff --git a/src/Artemis.Core/Plugins/LayerEffects/IEffectConfigurationViewModel.cs b/src/Artemis.Core/Plugins/LayerEffects/IEffectConfigurationViewModel.cs deleted file mode 100644 index 33aa630e9..000000000 --- a/src/Artemis.Core/Plugins/LayerEffects/IEffectConfigurationViewModel.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Artemis.Core.LayerEffects -{ - public interface IEffectConfigurationViewModel - { - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerEffects/ILayerEffectConfigurationDialog.cs b/src/Artemis.Core/Plugins/LayerEffects/ILayerEffectConfigurationDialog.cs index bafe13a1d..238e07a51 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/ILayerEffectConfigurationDialog.cs +++ b/src/Artemis.Core/Plugins/LayerEffects/ILayerEffectConfigurationDialog.cs @@ -1,5 +1,8 @@ namespace Artemis.Core.LayerEffects { + /// + /// Represents a configuration dialog for a + /// public interface ILayerEffectConfigurationDialog { } diff --git a/src/Artemis.Core/Plugins/Plugin.cs b/src/Artemis.Core/Plugins/Plugin.cs index 1182e8920..c881ef5fb 100644 --- a/src/Artemis.Core/Plugins/Plugin.cs +++ b/src/Artemis.Core/Plugins/Plugin.cs @@ -160,6 +160,7 @@ namespace Artemis.Core } } + /// public void Dispose() { foreach (PluginFeature feature in Features) diff --git a/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs b/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs index 2b5720296..9f322c566 100644 --- a/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs +++ b/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs @@ -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(); } diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index a3ab25712..4842b6880 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -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) diff --git a/src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs b/src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs index c85eba6b3..8dec2854b 100644 --- a/src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs +++ b/src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs @@ -44,6 +44,10 @@ namespace Artemis.Core.Services /// /// The plugin to enable /// Whether or not to save the new enabled state + /// + /// Whether or not plugin lock files should be ignored. If set to , + /// plugins with lock files will load successfully + /// void EnablePlugin(Plugin plugin, bool saveState, bool ignorePluginLock = false); /// @@ -95,7 +99,7 @@ namespace Artemis.Core.Services /// /// /// - Plugin GetPluginByAssembly(Assembly assembly); + Plugin? GetPluginByAssembly(Assembly? assembly); /// /// Returns the plugin info of the current call stack diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs index 4bcf40dcb..8817ae644 100644 --- a/src/Artemis.Core/Services/PluginManagementService.cs +++ b/src/Artemis.Core/Services/PluginManagementService.cs @@ -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().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 PluginLoading; - public event EventHandler PluginLoaded; - public event EventHandler PluginUnloaded; - public event EventHandler PluginEnabling; - public event EventHandler PluginEnabled; - public event EventHandler PluginDisabled; + public event EventHandler? CopyingBuildInPlugins; + public event EventHandler? PluginLoading; + public event EventHandler? PluginLoaded; + public event EventHandler? PluginUnloaded; + public event EventHandler? PluginEnabling; + public event EventHandler? PluginEnabled; + public event EventHandler? PluginDisabled; - public event EventHandler PluginFeatureEnabling; - public event EventHandler PluginFeatureEnabled; - public event EventHandler PluginFeatureDisabled; - public event EventHandler PluginFeatureEnableFailed; + public event EventHandler? PluginFeatureEnabling; + public event EventHandler? PluginFeatureEnabled; + public event EventHandler? PluginFeatureDisabled; + public event EventHandler? PluginFeatureEnableFailed; protected virtual void OnCopyingBuildInPlugins() { diff --git a/src/Artemis.Core/Services/Storage/SurfaceService.cs b/src/Artemis.Core/Services/Storage/SurfaceService.cs index 6b1fc1861..fe0d251eb 100644 --- a/src/Artemis.Core/Services/Storage/SurfaceService.cs +++ b/src/Artemis.Core/Services/Storage/SurfaceService.cs @@ -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); diff --git a/src/Artemis.Core/Stores/ConditionOperatorStore.cs b/src/Artemis.Core/Stores/ConditionOperatorStore.cs index 3247d648d..67edee873 100644 --- a/src/Artemis.Core/Stores/ConditionOperatorStore.cs +++ b/src/Artemis.Core/Stores/ConditionOperatorStore.cs @@ -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) { diff --git a/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs b/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs index 302f32241..e860777f3 100644 --- a/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs +++ b/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs @@ -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 DataBindingModifierAdded; - public static event EventHandler DataBindingModifierRemoved; + public static event EventHandler? DataBindingModifierAdded; + public static event EventHandler? DataBindingModifierRemoved; private static void OnDataBindingModifierAdded(DataBindingModifierTypeStoreEvent e) { diff --git a/src/Artemis.Core/Stores/DataModelStore.cs b/src/Artemis.Core/Stores/DataModelStore.cs index 713ee90c2..02e7a9603 100644 --- a/src/Artemis.Core/Stores/DataModelStore.cs +++ b/src/Artemis.Core/Stores/DataModelStore.cs @@ -47,7 +47,7 @@ namespace Artemis.Core } } - public static DataModelRegistration Get(string id) + public static DataModelRegistration? Get(string id) { lock (Registrations) { diff --git a/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs b/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs index 4c3a03463..e04096b22 100644 --- a/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs +++ b/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using System.Windows; namespace Artemis.Core { @@ -42,7 +41,7 @@ namespace Artemis.Core } /// - /// Opens the provided URL in the default web browser + /// Opens the provided URL in the default web browser /// /// The URL to open /// The process created to open the URL @@ -67,7 +66,10 @@ namespace Artemis.Core #region Events - public static event EventHandler ShutdownRequested; + /// + /// Occurs when the core has requested an application shutdown + /// + public static event EventHandler? ShutdownRequested; private static void OnShutdownRequested() { @@ -75,7 +77,5 @@ namespace Artemis.Core } #endregion - - } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj index 2e39dab75..2a0574570 100644 --- a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj +++ b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj @@ -28,6 +28,7 @@ git true 2.0.0 + enable bin\x64\Release\Artemis.UI.Shared.xml diff --git a/src/Artemis.UI.Shared/Services/DataModelUIService.cs b/src/Artemis.UI.Shared/Services/DataModelUIService.cs index bfcdb4da4..5554d6ed1 100644 --- a/src/Artemis.UI.Shared/Services/DataModelUIService.cs +++ b/src/Artemis.UI.Shared/Services/DataModelUIService.cs @@ -106,8 +106,8 @@ namespace Artemis.UI.Shared.Services if (existing != null) { if (existing.Plugin != plugin) - throw new ArtemisPluginException($"Cannot register data model input for type {supportedType.Name} because an editor was already" + - $" registered by {existing.Plugin}"); + throw new ArtemisSharedUIException($"Cannot register data model input for type {supportedType.Name} because an editor was already" + + $" registered by {existing.Plugin}"); return existing; } @@ -135,8 +135,8 @@ namespace Artemis.UI.Shared.Services if (existing != null) { if (existing.Plugin != plugin) - throw new ArtemisPluginException($"Cannot register data model display for type {supportedType.Name} because an editor was already" + - $" registered by {existing.Plugin}"); + throw new ArtemisSharedUIException($"Cannot register data model display for type {supportedType.Name} because an editor was already" + + $" registered by {existing.Plugin}"); return existing; } diff --git a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs index 0dca8e593..44e37b6a2 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs @@ -202,8 +202,8 @@ namespace Artemis.UI.Shared.Services if (existing != null) { if (existing.Plugin != plugin) - throw new ArtemisPluginException($"Cannot register property editor for type {supportedType.Name} because an editor was already " + - $"registered by {existing.Plugin}"); + throw new ArtemisSharedUIException($"Cannot register property editor for type {supportedType.Name} because an editor was already " + + $"registered by {existing.Plugin}"); return existing; } diff --git a/src/Artemis.UI/Behaviors/TreeViewSelectionBehavior.cs b/src/Artemis.UI/Behaviors/TreeViewSelectionBehavior.cs index 1e5acda30..11de9ea70 100644 --- a/src/Artemis.UI/Behaviors/TreeViewSelectionBehavior.cs +++ b/src/Artemis.UI/Behaviors/TreeViewSelectionBehavior.cs @@ -118,7 +118,7 @@ namespace Artemis.UI.Behaviors // Recurse into children if (recurse) { - foreach (object? subitem in item.Items) + foreach (object subitem in item.Items) { TreeViewItem tvi = item.ItemContainerGenerator.ContainerFromItem(subitem) as TreeViewItem; if (tvi != null) @@ -131,7 +131,7 @@ namespace Artemis.UI.Behaviors private void UpdateAllTreeViewItems() { TreeView treeView = AssociatedObject; - foreach (object? item in treeView.Items) + foreach (object item in treeView.Items) { TreeViewItem tvi = treeView.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem; if (tvi != null) diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs index d64e10620..af915cf32 100644 --- a/src/Artemis.UI/Bootstrapper.cs +++ b/src/Artemis.UI/Bootstrapper.cs @@ -118,7 +118,7 @@ namespace Artemis.UI e.Handled = true; } - private void UtilitiesOnShutdownRequested(object? sender, EventArgs e) + private void UtilitiesOnShutdownRequested(object sender, EventArgs e) { Execute.OnUIThread(() => Application.Current.Shutdown()); } diff --git a/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugViewModel.cs b/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugViewModel.cs index f5b534518..9bfac70e9 100644 --- a/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugViewModel.cs @@ -55,7 +55,7 @@ namespace Artemis.UI.Screens.Settings.Debug { try { - Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.PluginFeature.Plugin.Directory.FullName); + Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.DeviceProvider.Plugin.Directory.FullName); } catch (Exception e) { diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs index a89933790..e2b2333ba 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs @@ -60,7 +60,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices { try { - Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.PluginFeature.Plugin.Directory.FullName); + Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.DeviceProvider.Plugin.Directory.FullName); } catch (Exception e) { diff --git a/src/Artemis.sln.DotSettings b/src/Artemis.sln.DotSettings index 2df38068d..8578a1102 100644 --- a/src/Artemis.sln.DotSettings +++ b/src/Artemis.sln.DotSettings @@ -215,6 +215,7 @@ True False True + SK UI True True