diff --git a/src/Artemis.ConsoleUI/packages.lock.json b/src/Artemis.ConsoleUI/packages.lock.json
index bbb02c9a2..feeaa74a8 100644
--- a/src/Artemis.ConsoleUI/packages.lock.json
+++ b/src/Artemis.ConsoleUI/packages.lock.json
@@ -313,13 +313,10 @@
},
"Serilog.Sinks.Console": {
"type": "Transitive",
- "resolved": "3.1.1",
- "contentHash": "56mI5AqvyF/i/c2451nvV71kq370XOCE4Uu5qiaJ295sOhMb9q3BWwG7mWLOVSnmpWiq0SBT3SXfgRXGNP6vzA==",
+ "resolved": "4.0.0",
+ "contentHash": "yJQit9sTJ4xGLKgCujqDJsaGqBNJwGB/H898z+xYlMG06twy4//6LLnSrsmpduZxcHIG4im7cv+JmXLzXz2EkQ==",
"dependencies": {
- "Serilog": "2.5.0",
- "System.Console": "4.3.0",
- "System.Runtime.InteropServices": "4.3.0",
- "System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
+ "Serilog": "2.10.0"
}
},
"Serilog.Sinks.Debug": {
@@ -332,19 +329,16 @@
},
"Serilog.Sinks.File": {
"type": "Transitive",
- "resolved": "4.1.0",
- "contentHash": "U0b34w+ZikbqWEZ3ui7BdzxY/19zwrdhLtI3o6tfmLdD3oXxg7n2TZJjwCCTlKPgRuYic9CBWfrZevbb70mTaw==",
+ "resolved": "5.0.0",
+ "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
"dependencies": {
- "Serilog": "2.5.0",
- "System.IO.FileSystem": "4.0.1",
- "System.Text.Encoding.Extensions": "4.0.11",
- "System.Threading.Timer": "4.0.1"
+ "Serilog": "2.10.0"
}
},
"SkiaSharp": {
"type": "Transitive",
- "resolved": "2.80.2",
- "contentHash": "D25rzdCwh+3L+XyXqpNa+H/yiLJbE3/R3K/XexwHyQjGdzZvSufFW3oqf3En7hhqSIsxsJ8f5NEZ0J5W5wlGBg==",
+ "resolved": "2.80.3",
+ "contentHash": "qX6tGNP3+MXNYe2pKm0PCRiJ/cx+LTeLaggwZifB7sUMXhECfKKKHJq45VqZKt37xQegnCCdf1jHXwmHeJQs5Q==",
"dependencies": {
"System.Memory": "4.5.3"
}
@@ -1230,10 +1224,10 @@
"Ninject.Extensions.ChildKernel": "3.3.0",
"Ninject.Extensions.Conventions": "3.3.0",
"Serilog": "2.10.0",
- "Serilog.Sinks.Console": "3.1.1",
+ "Serilog.Sinks.Console": "4.0.0",
"Serilog.Sinks.Debug": "2.0.0",
- "Serilog.Sinks.File": "4.1.0",
- "SkiaSharp": "2.80.2",
+ "Serilog.Sinks.File": "5.0.0",
+ "SkiaSharp": "2.80.3",
"System.Buffers": "4.5.1",
"System.IO.FileSystem.AccessControl": "5.0.0",
"System.Numerics.Vectors": "4.5.0",
diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj
index 4cb259807..f73a999ab 100644
--- a/src/Artemis.Core/Artemis.Core.csproj
+++ b/src/Artemis.Core/Artemis.Core.csproj
@@ -48,10 +48,10 @@
-
+
-
-
+
+
diff --git a/src/Artemis.Core/Constants.cs b/src/Artemis.Core/Constants.cs
index e978e8598..7921af0bc 100644
--- a/src/Artemis.Core/Constants.cs
+++ b/src/Artemis.Core/Constants.cs
@@ -27,7 +27,7 @@ namespace Artemis.Core
///
/// The full path to the Artemis data folder
///
- public static readonly string DataFolder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\Artemis\\";
+ public static readonly string DataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Artemis");
///
/// The plugin info used by core components of Artemis
diff --git a/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs b/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs
index 8d46099e0..245b9eeb1 100644
--- a/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs
+++ b/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs
@@ -169,29 +169,29 @@ namespace Artemis.Core
internal static ArtemisLayout? GetDefaultLayout(ArtemisDevice device)
{
- string layoutFolder = Path.Combine(Constants.ApplicationFolder, "DefaultLayouts\\Artemis");
+ string layoutFolder = Path.Combine(Constants.ApplicationFolder, "DefaultLayouts", "Artemis");
if (device.DeviceType == RGBDeviceType.Keyboard)
{
// XL layout is defined by its programmable macro keys
if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_Programmable1 && l.RgbLed.Id <= LedId.Keyboard_Programmable32))
{
if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
- return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis XL keyboard-ANSI.xml", LayoutSource.Default);
- return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis XL keyboard-ISO.xml", LayoutSource.Default);
+ return new ArtemisLayout(Path.Combine(layoutFolder, "Keyboard", "Artemis XL keyboard-ANSI.xml"), LayoutSource.Default);
+ return new ArtemisLayout(Path.Combine(layoutFolder, "Keyboard", "Artemis XL keyboard-ISO.xml"), LayoutSource.Default);
}
// L layout is defined by its numpad
if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_NumLock && l.RgbLed.Id <= LedId.Keyboard_NumPeriodAndDelete))
{
if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
- return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis L keyboard-ANSI.xml", LayoutSource.Default);
- return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis L keyboard-ISO.xml", LayoutSource.Default);
+ return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard","Artemis L keyboard-ANSI.xml"), LayoutSource.Default);
+ return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard","Artemis L keyboard-ISO.xml"), LayoutSource.Default);
}
// No numpad will result in TKL
if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
- return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis TKL keyboard-ANSI.xml", LayoutSource.Default);
- return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis TKL keyboard-ISO.xml", LayoutSource.Default);
+ return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard","Artemis TKL keyboard-ANSI.xml"), LayoutSource.Default);
+ return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard","Artemis TKL keyboard-ISO.xml"), LayoutSource.Default);
}
// if (device.DeviceType == RGBDeviceType.Mouse)
@@ -199,21 +199,21 @@ namespace Artemis.Core
// if (device.Leds.Count == 1)
// {
// if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo))
- // return new ArtemisLayout(layoutFolder + "\\Mouse\\1 LED mouse logo.xml", LayoutSource.Default);
- // return new ArtemisLayout(layoutFolder + "\\Mouse\\1 LED mouse.xml", LayoutSource.Default);
+ // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "1 LED mouse logo.xml"), LayoutSource.Default);
+ // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "1 LED mouse.xml"), LayoutSource.Default);
// }
// if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo))
- // return new ArtemisLayout(layoutFolder + "\\Mouse\\4 LED mouse logo.xml", LayoutSource.Default);
- // return new ArtemisLayout(layoutFolder + "\\Mouse\\4 LED mouse.xml", LayoutSource.Default);
+ // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "4 LED mouse logo.xml"), LayoutSource.Default);
+ // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "4 LED mouse.xml"), LayoutSource.Default);
// }
if (device.DeviceType == RGBDeviceType.Headset)
{
if (device.Leds.Count == 1)
- return new ArtemisLayout(layoutFolder + "\\Headset\\Artemis 1 LED headset.xml", LayoutSource.Default);
+ return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 1 LED headset.xml"), LayoutSource.Default);
if (device.Leds.Count == 2)
- return new ArtemisLayout(layoutFolder + "\\Headset\\Artemis 2 LED headset.xml", LayoutSource.Default);
- return new ArtemisLayout(layoutFolder + "\\Headset\\Artemis 4 LED headset.xml", LayoutSource.Default);
+ return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 2 LED headset.xml"), LayoutSource.Default);
+ return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 4 LED headset.xml"), LayoutSource.Default);
}
return null;
diff --git a/src/Artemis.Core/Models/Surface/Layout/ArtemisLedLayout.cs b/src/Artemis.Core/Models/Surface/Layout/ArtemisLedLayout.cs
index 838c62881..01fcce12d 100644
--- a/src/Artemis.Core/Models/Surface/Layout/ArtemisLedLayout.cs
+++ b/src/Artemis.Core/Models/Surface/Layout/ArtemisLedLayout.cs
@@ -61,7 +61,6 @@ namespace Artemis.Core
if (LayoutCustomLedData.LogicalLayouts == null || !LayoutCustomLedData.LogicalLayouts.Any())
return;
- Uri layoutDirectory = new(Path.GetDirectoryName(DeviceLayout.FilePath)! + "\\", UriKind.Absolute);
// Prefer a matching layout or else a default layout (that has no name)
LayoutCustomLedDataLogicalLayout logicalLayout = LayoutCustomLedData.LogicalLayouts
.OrderBy(l => l.Name == artemisDevice.LogicalLayout)
@@ -69,7 +68,7 @@ namespace Artemis.Core
.First();
LogicalName = logicalLayout.Name;
- Image = new Uri(layoutDirectory, logicalLayout.Image);
+ Image = new Uri(Path.Combine(Path.GetDirectoryName(DeviceLayout.FilePath)!, logicalLayout.Image!), UriKind.Absolute);
}
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Ninject/LoggerProvider.cs b/src/Artemis.Core/Ninject/LoggerProvider.cs
index c39f7bace..64f5efcf3 100644
--- a/src/Artemis.Core/Ninject/LoggerProvider.cs
+++ b/src/Artemis.Core/Ninject/LoggerProvider.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using Ninject.Activation;
using Serilog;
using Serilog.Core;
@@ -12,7 +13,7 @@ namespace Artemis.Core.Ninject
private static readonly ILogger Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
- .WriteTo.File(Constants.DataFolder + "logs/Artemis log-.log",
+ .WriteTo.File(Path.Combine(Constants.DataFolder, "logs", "Artemis log-.log"),
rollingInterval: RollingInterval.Day,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}")
.WriteTo.Console()
diff --git a/src/Artemis.Core/Plugins/PluginFeature.cs b/src/Artemis.Core/Plugins/PluginFeature.cs
index 983f20438..7d58d31cb 100644
--- a/src/Artemis.Core/Plugins/PluginFeature.cs
+++ b/src/Artemis.Core/Plugins/PluginFeature.cs
@@ -11,8 +11,8 @@ namespace Artemis.Core
public abstract class PluginFeature : CorePropertyChanged, IDisposable
{
private bool _isEnabled;
- private Exception? _loadException;
-
+
+
///
/// Gets the plugin feature info related to this feature
///
@@ -37,14 +37,7 @@ namespace Artemis.Core
internal set => SetAndNotify(ref _isEnabled, value);
}
- ///
- /// Gets the exception thrown while loading
- ///
- public Exception? LoadException
- {
- get => _loadException;
- internal set => SetAndNotify(ref _loadException, value);
- }
+ internal int AutoEnableAttempts { get; set; }
///
/// Gets the identifier of this plugin feature
@@ -82,7 +75,8 @@ namespace Artemis.Core
///
protected virtual void Dispose(bool disposing)
{
- if (disposing) InternalDisable();
+ if (disposing)
+ SetEnabled(false);
}
///
@@ -111,16 +105,6 @@ namespace Artemis.Core
Profiler.StopMeasurement("Update");
}
- internal void StartRenderMeasure()
- {
- Profiler.StartMeasurement("Render");
- }
-
- internal void StopRenderMeasure()
- {
- Profiler.StopMeasurement("Render");
- }
-
internal void SetEnabled(bool enable, bool isAutoEnable = false)
{
if (enable == IsEnabled)
@@ -146,13 +130,16 @@ namespace Artemis.Core
try
{
+ if (isAutoEnable)
+ AutoEnableAttempts++;
+
if (isAutoEnable && GetLockFileCreated())
{
// Don't wrap existing lock exceptions, simply rethrow them
- if (LoadException is ArtemisPluginLockException)
- throw LoadException;
+ if (Info.LoadException is ArtemisPluginLockException)
+ throw Info.LoadException;
- throw new ArtemisPluginLockException(LoadException);
+ throw new ArtemisPluginLockException(Info.LoadException);
}
CreateLockFile();
@@ -165,21 +152,22 @@ namespace Artemis.Core
if (!enableTask.Wait(TimeSpan.FromSeconds(15)))
throw new ArtemisPluginException(Plugin, "Plugin load timeout");
- LoadException = null;
+ Info.LoadException = null;
+ AutoEnableAttempts = 0;
OnEnabled();
}
// If enable failed, put it back in a disabled state
catch (Exception e)
{
IsEnabled = false;
- LoadException = e;
+ Info.LoadException = e;
throw;
}
finally
{
// Clean up the lock file unless the failure was due to the lock file
// After all, we failed but not miserably :)
- if (!(LoadException is ArtemisPluginLockException))
+ if (Info.LoadException is not ArtemisPluginLockException)
DeleteLockFile();
}
}
diff --git a/src/Artemis.Core/Plugins/PluginFeatureInfo.cs b/src/Artemis.Core/Plugins/PluginFeatureInfo.cs
index 4947ab20a..62b4a6c5c 100644
--- a/src/Artemis.Core/Plugins/PluginFeatureInfo.cs
+++ b/src/Artemis.Core/Plugins/PluginFeatureInfo.cs
@@ -17,6 +17,7 @@ namespace Artemis.Core
[JsonObject(MemberSerialization.OptIn)]
public class PluginFeatureInfo : CorePropertyChanged, IPrerequisitesSubject
{
+ private Exception? _loadException;
private string? _description;
private string? _icon;
private PluginFeature? _instance;
@@ -80,6 +81,15 @@ namespace Artemis.Core
///
public Type FeatureType { get; }
+ ///
+ /// Gets the exception thrown while loading
+ ///
+ public Exception? LoadException
+ {
+ get => _loadException;
+ internal set => SetAndNotify(ref _loadException, value);
+ }
+
///
/// The name of the plugin
///
diff --git a/src/Artemis.Core/Services/ColorQuantizer/ColorQuantizerService.cs b/src/Artemis.Core/Services/ColorQuantizer/ColorQuantizerService.cs
index 4fe7d22c4..f61b70dd5 100644
--- a/src/Artemis.Core/Services/ColorQuantizer/ColorQuantizerService.cs
+++ b/src/Artemis.Core/Services/ColorQuantizer/ColorQuantizerService.cs
@@ -8,21 +8,6 @@ namespace Artemis.Core.Services
///
internal class ColorQuantizerService : IColorQuantizerService
{
- private static float GetComparisonValue(float sat, float targetSaturation, float luma, float targetLuma)
- {
- static float InvertDiff(float value, float target)
- {
- return 1 - Math.Abs(value - target);
- }
-
- const float totalWeight = weightSaturation + weightLuma;
-
- float totalValue = InvertDiff(sat, targetSaturation) * weightSaturation +
- InvertDiff(luma, targetLuma) * weightLuma;
-
- return totalValue / totalWeight;
- }
-
///
public SKColor[] Quantize(IEnumerable colors, int amount)
{
@@ -48,29 +33,12 @@ namespace Artemis.Core.Services
///
public SKColor FindColorVariation(IEnumerable colors, ColorType type, bool ignoreLimits = false)
{
- (float targetLuma, float minLuma, float maxLuma, float targetSaturation, float minSaturation, float maxSaturation) = type switch
- {
- ColorType.Vibrant => (targetNormalLuma, minNormalLuma, maxNormalLuma, targetVibrantSaturation, minVibrantSaturation, 1f),
- ColorType.LightVibrant => (targetLightLuma, minLightLuma, 1f, targetVibrantSaturation, minVibrantSaturation, 1f),
- ColorType.DarkVibrant => (targetDarkLuma, 0f, maxDarkLuma, targetVibrantSaturation, minVibrantSaturation, 1f),
- ColorType.Muted => (targetNormalLuma, minNormalLuma, maxNormalLuma, targetMutesSaturation, 0, maxMutesSaturation),
- ColorType.LightMuted => (targetLightLuma, minLightLuma, 1f, targetMutesSaturation, 0, maxMutesSaturation),
- ColorType.DarkMuted => (targetDarkLuma, 0, maxDarkLuma, targetMutesSaturation, 0, maxMutesSaturation),
- _ => (0.5f, 0f, 1f, 0.5f, 0f, 1f)
- };
-
- float bestColorScore = float.MinValue;
+ float bestColorScore = 0;
SKColor bestColor = SKColor.Empty;
+
foreach (SKColor clr in colors)
{
- clr.ToHsl(out float _, out float sat, out float luma);
- sat /= 100f;
- luma /= 100f;
-
- if (!ignoreLimits && (sat <= minSaturation || sat >= maxSaturation || luma <= minLuma || luma >= maxLuma))
- continue;
-
- float score = GetComparisonValue(sat, targetSaturation, luma, targetLuma);
+ float score = GetScore(clr, type, ignoreLimits);
if (score > bestColorScore)
{
bestColorScore = score;
@@ -81,6 +49,82 @@ namespace Artemis.Core.Services
return bestColor;
}
+ ///
+ public ColorSwatch FindAllColorVariations(IEnumerable colors, bool ignoreLimits = false)
+ {
+ SKColor bestVibrantColor = SKColor.Empty;
+ SKColor bestLightVibrantColor = SKColor.Empty;
+ SKColor bestDarkVibrantColor = SKColor.Empty;
+ SKColor bestMutedColor = SKColor.Empty;
+ SKColor bestLightMutedColor = SKColor.Empty;
+ SKColor bestDarkMutedColor = SKColor.Empty;
+ float bestVibrantScore = 0;
+ float bestLightVibrantScore = 0;
+ float bestDarkVibrantScore = 0;
+ float bestMutedScore = 0;
+ float bestLightMutedScore = 0;
+ float bestDarkMutedScore = 0;
+
+ //ugly but at least we only loop through the enumerable once ¯\_(ツ)_/¯
+ foreach (var color in colors)
+ {
+ static void SetIfBetterScore(ref float bestScore, ref SKColor bestColor, SKColor newColor, ColorType type, bool ignoreLimits)
+ {
+ float newScore = GetScore(newColor, type, ignoreLimits);
+ if (newScore > bestScore)
+ {
+ bestScore = newScore;
+ bestColor = newColor;
+ }
+ }
+
+ SetIfBetterScore(ref bestVibrantScore, ref bestVibrantColor, color, ColorType.Vibrant, ignoreLimits);
+ SetIfBetterScore(ref bestLightVibrantScore, ref bestLightVibrantColor, color, ColorType.LightVibrant, ignoreLimits);
+ SetIfBetterScore(ref bestDarkVibrantScore, ref bestDarkVibrantColor, color, ColorType.DarkVibrant, ignoreLimits);
+ SetIfBetterScore(ref bestMutedScore, ref bestMutedColor, color, ColorType.Muted, ignoreLimits);
+ SetIfBetterScore(ref bestLightMutedScore, ref bestLightMutedColor, color, ColorType.LightMuted, ignoreLimits);
+ SetIfBetterScore(ref bestDarkMutedScore, ref bestDarkMutedColor, color, ColorType.DarkMuted, ignoreLimits);
+ }
+
+ return new()
+ {
+ Vibrant = bestVibrantColor,
+ LightVibrant = bestLightVibrantColor,
+ DarkVibrant = bestDarkVibrantColor,
+ Muted = bestMutedColor,
+ LightMuted = bestLightMutedColor,
+ DarkMuted = bestDarkMutedColor,
+ };
+ }
+
+ private static float GetScore(SKColor color, ColorType type, bool ignoreLimits = false)
+ {
+ static float InvertDiff(float value, float target)
+ {
+ return 1 - Math.Abs(value - target);
+ }
+
+ color.ToHsl(out float _, out float saturation, out float luma);
+ saturation /= 100f;
+ luma /= 100f;
+
+ if (!ignoreLimits &&
+ (saturation <= GetMinSaturation(type) || saturation >= GetMaxSaturation(type)
+ || luma <= GetMinLuma(type) || luma >= GetMaxLuma(type)))
+ {
+ //if either saturation or luma falls outside the min-max, return the
+ //lowest score possible unless we're ignoring these limits.
+ return float.MinValue;
+ }
+
+ float totalValue = (InvertDiff(saturation, GetTargetSaturation(type)) * weightSaturation) +
+ (InvertDiff(luma, GetTargetLuma(type)) * weightLuma);
+
+ const float totalWeight = weightSaturation + weightLuma;
+
+ return totalValue / totalWeight;
+ }
+
#region Constants
private const float targetDarkLuma = 0.26f;
@@ -97,6 +141,72 @@ namespace Artemis.Core.Services
private const float weightSaturation = 3f;
private const float weightLuma = 5f;
+ private static float GetTargetLuma(ColorType colorType) => colorType switch
+ {
+ ColorType.Vibrant => targetNormalLuma,
+ ColorType.LightVibrant => targetLightLuma,
+ ColorType.DarkVibrant => targetDarkLuma,
+ ColorType.Muted => targetNormalLuma,
+ ColorType.LightMuted => targetLightLuma,
+ ColorType.DarkMuted => targetDarkLuma,
+ _ => throw new ArgumentException(nameof(colorType))
+ };
+
+ private static float GetMinLuma(ColorType colorType) => colorType switch
+ {
+ ColorType.Vibrant => minNormalLuma,
+ ColorType.LightVibrant => minLightLuma,
+ ColorType.DarkVibrant => 0f,
+ ColorType.Muted => minNormalLuma,
+ ColorType.LightMuted => minLightLuma,
+ ColorType.DarkMuted => 0,
+ _ => throw new ArgumentException(nameof(colorType))
+ };
+
+ private static float GetMaxLuma(ColorType colorType) => colorType switch
+ {
+ ColorType.Vibrant => maxNormalLuma,
+ ColorType.LightVibrant => 1f,
+ ColorType.DarkVibrant => maxDarkLuma,
+ ColorType.Muted => maxNormalLuma,
+ ColorType.LightMuted => 1f,
+ ColorType.DarkMuted => maxDarkLuma,
+ _ => throw new ArgumentException(nameof(colorType))
+ };
+
+ private static float GetTargetSaturation(ColorType colorType) => colorType switch
+ {
+ ColorType.Vibrant => targetVibrantSaturation,
+ ColorType.LightVibrant => targetVibrantSaturation,
+ ColorType.DarkVibrant => targetVibrantSaturation,
+ ColorType.Muted => targetMutesSaturation,
+ ColorType.LightMuted => targetMutesSaturation,
+ ColorType.DarkMuted => targetMutesSaturation,
+ _ => throw new ArgumentException(nameof(colorType))
+ };
+
+ private static float GetMinSaturation(ColorType colorType) => colorType switch
+ {
+ ColorType.Vibrant => minVibrantSaturation,
+ ColorType.LightVibrant => minVibrantSaturation,
+ ColorType.DarkVibrant => minVibrantSaturation,
+ ColorType.Muted => 0,
+ ColorType.LightMuted => 0,
+ ColorType.DarkMuted => 0,
+ _ => throw new ArgumentException(nameof(colorType))
+ };
+
+ private static float GetMaxSaturation(ColorType colorType) => colorType switch
+ {
+ ColorType.Vibrant => 1f,
+ ColorType.LightVibrant => 1f,
+ ColorType.DarkVibrant => 1f,
+ ColorType.Muted => maxMutesSaturation,
+ ColorType.LightMuted => maxMutesSaturation,
+ ColorType.DarkMuted => maxMutesSaturation,
+ _ => throw new ArgumentException(nameof(colorType))
+ };
+
#endregion
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/ColorQuantizer/ColorSwatch.cs b/src/Artemis.Core/Services/ColorQuantizer/ColorSwatch.cs
new file mode 100644
index 000000000..81abb7cc2
--- /dev/null
+++ b/src/Artemis.Core/Services/ColorQuantizer/ColorSwatch.cs
@@ -0,0 +1,40 @@
+using SkiaSharp;
+
+namespace Artemis.Core.Services
+{
+ ///
+ /// Swatch containing the known useful color variations.
+ ///
+ public struct ColorSwatch
+ {
+ ///
+ /// The component.
+ ///
+ public SKColor Vibrant { get; init; }
+
+ ///
+ /// The component.
+ ///
+ public SKColor LightVibrant { get; init; }
+
+ ///
+ /// The component.
+ ///
+ public SKColor DarkVibrant { get; init; }
+
+ ///
+ /// The component.
+ ///
+ public SKColor Muted { get; init; }
+
+ ///
+ /// The component.
+ ///
+ public SKColor LightMuted { get; init; }
+
+ ///
+ /// The component.
+ ///
+ public SKColor DarkMuted { get; init; }
+ }
+}
diff --git a/src/Artemis.Core/Services/ColorQuantizer/Interfaces/IColorQuantizerService.cs b/src/Artemis.Core/Services/ColorQuantizer/Interfaces/IColorQuantizerService.cs
index 6b0971684..82d70715a 100644
--- a/src/Artemis.Core/Services/ColorQuantizer/Interfaces/IColorQuantizerService.cs
+++ b/src/Artemis.Core/Services/ColorQuantizer/Interfaces/IColorQuantizerService.cs
@@ -26,5 +26,13 @@ namespace Artemis.Core.Services
/// Ignore hard limits on whether a color is considered for each category. Result may be if this is false
/// The color found
public SKColor FindColorVariation(IEnumerable colors, ColorType type, bool ignoreLimits = false);
+
+ ///
+ /// Finds all the color variations available and returns a struct containing them all.
+ ///
+ /// The colors to find the variations in
+ /// Ignore hard limits on whether a color is considered for each category. Some colors may be if this is false
+ /// A swatch containing all color variations
+ public ColorSwatch FindAllColorVariations(IEnumerable colors, bool ignoreLimits = false);
}
}
diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs
index 7d9575166..25bc3cae9 100644
--- a/src/Artemis.Core/Services/CoreService.cs
+++ b/src/Artemis.Core/Services/CoreService.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
+using System.Threading;
using System.Threading.Tasks;
using Artemis.Core.Ninject;
using Artemis.Core.ScriptingProviders;
@@ -13,7 +14,6 @@ using RGB.NET.Core;
using Serilog;
using Serilog.Events;
using SkiaSharp;
-using Module = Artemis.Core.Modules.Module;
namespace Artemis.Core.Services
{
@@ -59,7 +59,6 @@ namespace Artemis.Core.Services
_frameStopWatch = new Stopwatch();
StartupArguments = new List();
- _rgbService.IsRenderPaused = true;
_rgbService.Surface.Updating += SurfaceOnUpdating;
_loggingLevel.SettingChanged += (sender, args) => ApplyLoggingLevel();
}
@@ -107,6 +106,13 @@ namespace Artemis.Core.Services
if (_rgbService.IsRenderPaused)
return;
+ if (_rgbService.FlushLeds)
+ {
+ _rgbService.FlushLeds = false;
+ _rgbService.Surface.Update(true);
+ return;
+ }
+
try
{
_frameStopWatch.Restart();
@@ -214,7 +220,7 @@ namespace Artemis.Core.Services
_pluginManagementService.CopyBuiltInPlugins();
_pluginManagementService.LoadPlugins(StartupArguments, IsElevated);
- _rgbService.IsRenderPaused = false;
+ _rgbService.SetRenderPaused(false);
OnInitialized();
}
diff --git a/src/Artemis.Core/Services/Interfaces/IRgbService.cs b/src/Artemis.Core/Services/Interfaces/IRgbService.cs
index 10ec9fa1b..c9bed101a 100644
--- a/src/Artemis.Core/Services/Interfaces/IRgbService.cs
+++ b/src/Artemis.Core/Services/Interfaces/IRgbService.cs
@@ -34,12 +34,17 @@ namespace Artemis.Core.Services
///
/// Gets or sets whether rendering should be paused
///
- bool IsRenderPaused { get; set; }
+ bool IsRenderPaused { get; }
///
/// Gets a boolean indicating whether the render pipeline is open
///
bool RenderOpen { get; }
+
+ ///
+ /// Gets or sets a boolean indicating whether to flush the RGB.NET LEDs during next update
+ ///
+ bool FlushLeds { get; set; }
///
/// Opens the render pipeline
@@ -133,6 +138,13 @@ namespace Artemis.Core.Services
/// The device to disable
void DisableDevice(ArtemisDevice device);
+ ///
+ /// Pauses or resumes rendering, method won't return until the current frame finished rendering
+ ///
+ ///
+ /// if the pause state was changed; otherwise .
+ bool SetRenderPaused(bool paused);
+
///
/// Occurs when a single device was added
///
diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs
index 00a74d2a5..5e4841829 100644
--- a/src/Artemis.Core/Services/PluginManagementService.cs
+++ b/src/Artemis.Core/Services/PluginManagementService.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
+using System.Threading.Tasks;
using Artemis.Core.DeviceProviders;
using Artemis.Core.Ninject;
using Artemis.Storage.Entities.General;
@@ -90,11 +91,6 @@ namespace Artemis.Core.Services
using StreamReader reader = new(metaDataFileEntry.Open());
PluginInfo builtInPluginInfo = CoreJson.DeserializeObject(reader.ReadToEnd())!;
string preferred = builtInPluginInfo.PreferredPluginDirectory;
- string oldPreferred = Path.GetFileNameWithoutExtension(zipFile.Name);
- // Rename folders to the new format
- // TODO: Get rid of this eventually, it's nice to keep around but it's extra IO that's best avoided
- if (pluginDirectory.EnumerateDirectories().FirstOrDefault(d => d.Name == oldPreferred) != null)
- Directory.Move(Path.Combine(pluginDirectory.FullName, oldPreferred), Path.Combine(pluginDirectory.FullName, preferred));
// Find the matching plugin in the plugin folder
DirectoryInfo? match = pluginDirectory.EnumerateDirectories().FirstOrDefault(d => d.Name == preferred);
@@ -431,6 +427,7 @@ namespace Artemis.Core.Services
catch (Exception e)
{
_logger.Warning(new ArtemisPluginException(plugin, "Failed to instantiate feature", e), "Failed to instantiate feature", plugin);
+ featureInfo.LoadException = e;
}
}
@@ -614,10 +611,38 @@ namespace Artemis.Core.Services
}
catch (Exception e)
{
- _logger.Warning(
- new ArtemisPluginException(pluginFeature.Plugin, $"Exception during SetEnabled(true) on {pluginFeature}", e),
- "Failed to enable plugin"
- );
+ if (isAutoEnable)
+ {
+ // Schedule a retry based on the amount of attempts
+ if (pluginFeature.AutoEnableAttempts < 4)
+ {
+ TimeSpan retryDelay = TimeSpan.FromSeconds(pluginFeature.AutoEnableAttempts * 10);
+ _logger.Warning(
+ e,
+ "Plugin feature '{feature} - {plugin}' failed to enable during attempt ({attempt}/3), scheduling a retry in {retryDelay}.",
+ pluginFeature,
+ pluginFeature.Plugin,
+ pluginFeature.AutoEnableAttempts,
+ retryDelay
+ );
+
+ Task.Run(async () =>
+ {
+ await Task.Delay(retryDelay);
+ if (!pluginFeature.IsEnabled)
+ EnablePluginFeature(pluginFeature, saveState, true);
+ });
+ }
+ else
+ {
+ _logger.Warning(e, "Plugin feature '{feature} - {plugin}' failed to enable after 3 attempts, giving up.", pluginFeature, pluginFeature.Plugin);
+ }
+ }
+ else
+ {
+ _logger.Warning(e, "Plugin feature '{feature} - {plugin}' failed to enable.", pluginFeature, pluginFeature.Plugin);
+ throw;
+ }
}
finally
{
diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs
index feff46dc2..1922b4c64 100644
--- a/src/Artemis.Core/Services/RgbService.cs
+++ b/src/Artemis.Core/Services/RgbService.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.IO;
using System.Linq;
using System.Threading;
using Artemis.Core.DeviceProviders;
@@ -28,7 +27,6 @@ namespace Artemis.Core.Services
private readonly PluginSetting _targetFrameRateSetting;
private readonly TextureBrush _textureBrush = new(ITexture.Empty) {CalculationMode = RenderMode.Absolute};
private Dictionary _ledMap;
- private bool _modifyingProviders;
private ListLedGroup? _surfaceLedGroup;
private SKTexture? _texture;
@@ -52,8 +50,9 @@ namespace Artemis.Core.Services
_ledMap = new Dictionary();
UpdateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value};
+ SetRenderPaused(true);
Surface.RegisterUpdateTrigger(UpdateTrigger);
-
+
Utilities.ShutdownRequested += UtilitiesOnShutdownRequested;
}
@@ -82,16 +81,14 @@ namespace Artemis.Core.Services
private void UpdateLedGroup()
{
- lock (_devices)
+ bool changedRenderPaused = SetRenderPaused(true);
+ try
{
- if (_modifyingProviders)
- return;
-
_ledMap = new Dictionary(_devices.SelectMany(d => d.Leds).ToDictionary(l => l.RgbLed));
if (_surfaceLedGroup == null)
{
- _surfaceLedGroup = new ListLedGroup(Surface, LedMap.Select(l => l.Key)) {Brush = _textureBrush};
+ _surfaceLedGroup = new ListLedGroup(Surface, LedMap.Select(l => l.Key)) { Brush = _textureBrush };
OnLedsChanged();
return;
}
@@ -102,10 +99,16 @@ namespace Artemis.Core.Services
_surfaceLedGroup.Detach();
// Apply the application wide brush and decorator
- _surfaceLedGroup = new ListLedGroup(Surface, LedMap.Select(l => l.Key)) {Brush = _textureBrush};
+ _surfaceLedGroup = new ListLedGroup(Surface, LedMap.Select(l => l.Key)) { Brush = _textureBrush };
OnLedsChanged();
}
}
+ finally
+ {
+ if (changedRenderPaused)
+ SetRenderPaused(false);
+ }
+
}
private void TargetFrameRateSettingOnSettingChanged(object? sender, EventArgs e)
@@ -137,91 +140,90 @@ namespace Artemis.Core.Services
public bool IsRenderPaused { get; set; }
public bool RenderOpen { get; private set; }
+ ///
+ public bool FlushLeds { get; set; }
+
public void AddDeviceProvider(IRGBDeviceProvider deviceProvider)
{
- lock (_devices)
+ bool changedRenderPaused = SetRenderPaused(true);
+
+ try
{
- try
+ List toRemove = _devices.Where(a => deviceProvider.Devices.Any(d => a.RgbDevice == d)).ToList();
+ Surface.Detach(toRemove.Select(d => d.RgbDevice));
+ foreach (ArtemisDevice device in toRemove)
+ RemoveDevice(device);
+
+ List providerExceptions = new();
+
+ void DeviceProviderOnException(object? sender, ExceptionEventArgs e)
{
- _modifyingProviders = true;
-
- List toRemove = _devices.Where(a => deviceProvider.Devices.Any(d => a.RgbDevice == d)).ToList();
- Surface.Detach(toRemove.Select(d => d.RgbDevice));
- foreach (ArtemisDevice device in toRemove)
- RemoveDevice(device);
-
- List providerExceptions = new();
-
- void DeviceProviderOnException(object? sender, ExceptionEventArgs e)
- {
- if (e.IsCritical)
- providerExceptions.Add(e.Exception);
- else
- _logger.Warning(e.Exception, "Device provider {deviceProvider} threw non-critical exception", deviceProvider.GetType().Name);
- }
-
- deviceProvider.Exception += DeviceProviderOnException;
- deviceProvider.Initialize();
- Surface.Attach(deviceProvider.Devices);
- deviceProvider.Exception -= DeviceProviderOnException;
- if (providerExceptions.Count == 1)
- throw new ArtemisPluginException("RGB.NET threw exception: " + providerExceptions.First().Message, providerExceptions.First());
- if (providerExceptions.Count > 1)
- throw new ArtemisPluginException("RGB.NET threw multiple exceptions", new AggregateException(providerExceptions));
-
- if (!deviceProvider.Devices.Any())
- {
- _logger.Warning("Device provider {deviceProvider} has no devices", deviceProvider.GetType().Name);
- return;
- }
-
- foreach (IRGBDevice rgbDevice in deviceProvider.Devices)
- {
- ArtemisDevice artemisDevice = GetArtemisDevice(rgbDevice);
- AddDevice(artemisDevice);
- _logger.Debug("Device provider {deviceProvider} added {deviceName}", deviceProvider.GetType().Name, rgbDevice.DeviceInfo.DeviceName);
- }
-
- _devices.Sort((a, b) => a.ZIndex - b.ZIndex);
+ if (e.IsCritical)
+ providerExceptions.Add(e.Exception);
+ else
+ _logger.Warning(e.Exception, "Device provider {deviceProvider} threw non-critical exception", deviceProvider.GetType().Name);
}
- catch (Exception e)
+
+ deviceProvider.Exception += DeviceProviderOnException;
+ deviceProvider.Initialize();
+ Surface.Attach(deviceProvider.Devices);
+ deviceProvider.Exception -= DeviceProviderOnException;
+ if (providerExceptions.Count == 1)
+ throw new ArtemisPluginException("RGB.NET threw exception: " + providerExceptions.First().Message, providerExceptions.First());
+ if (providerExceptions.Count > 1)
+ throw new ArtemisPluginException("RGB.NET threw multiple exceptions", new AggregateException(providerExceptions));
+
+ if (!deviceProvider.Devices.Any())
{
- _logger.Error(e, "Exception during device loading for device provider {deviceProvider}", deviceProvider.GetType().Name);
- throw;
+ _logger.Warning("Device provider {deviceProvider} has no devices", deviceProvider.GetType().Name);
+ return;
}
- finally
+
+ foreach (IRGBDevice rgbDevice in deviceProvider.Devices)
{
- _modifyingProviders = false;
- UpdateLedGroup();
+ ArtemisDevice artemisDevice = GetArtemisDevice(rgbDevice);
+ AddDevice(artemisDevice);
+ _logger.Debug("Device provider {deviceProvider} added {deviceName}", deviceProvider.GetType().Name, rgbDevice.DeviceInfo.DeviceName);
}
+
+ _devices.Sort((a, b) => a.ZIndex - b.ZIndex);
+ }
+ catch (Exception e)
+ {
+ _logger.Error(e, "Exception during device loading for device provider {deviceProvider}", deviceProvider.GetType().Name);
+ throw;
+ }
+ finally
+ {
+ UpdateLedGroup();
+ if (changedRenderPaused)
+ SetRenderPaused(false);
}
}
public void RemoveDeviceProvider(IRGBDeviceProvider deviceProvider)
{
- lock (_devices)
+ bool changedRenderPaused = SetRenderPaused(true);
+
+ try
{
- try
- {
- _modifyingProviders = true;
+ List toRemove = _devices.Where(a => deviceProvider.Devices.Any(d => a.RgbDevice == d)).ToList();
+ Surface.Detach(toRemove.Select(d => d.RgbDevice));
+ foreach (ArtemisDevice device in toRemove)
+ RemoveDevice(device);
- List toRemove = _devices.Where(a => deviceProvider.Devices.Any(d => a.RgbDevice == d)).ToList();
- Surface.Detach(toRemove.Select(d => d.RgbDevice));
- foreach (ArtemisDevice device in toRemove)
- RemoveDevice(device);
-
- _devices.Sort((a, b) => a.ZIndex - b.ZIndex);
- }
- catch (Exception e)
- {
- _logger.Error(e, "Exception during device removal for device provider {deviceProvider}", deviceProvider.GetType().Name);
- throw;
- }
- finally
- {
- _modifyingProviders = false;
- UpdateLedGroup();
- }
+ _devices.Sort((a, b) => a.ZIndex - b.ZIndex);
+ }
+ catch (Exception e)
+ {
+ _logger.Error(e, "Exception during device removal for device provider {deviceProvider}", deviceProvider.GetType().Name);
+ throw;
+ }
+ finally
+ {
+ UpdateLedGroup();
+ if (changedRenderPaused)
+ SetRenderPaused(false);
}
}
@@ -233,6 +235,24 @@ namespace Artemis.Core.Services
Surface.Dispose();
}
+ public bool SetRenderPaused(bool paused)
+ {
+ if (IsRenderPaused == paused)
+ return false;
+
+ if (paused)
+ {
+ UpdateTrigger.Stop();
+ }
+ else
+ {
+ UpdateTrigger.Start();
+ }
+
+ IsRenderPaused = paused;
+ return true;
+ }
+
public event EventHandler? DeviceAdded;
public event EventHandler? DeviceRemoved;
public event EventHandler? LedsChanged;
@@ -267,36 +287,39 @@ namespace Artemis.Core.Services
if (RenderOpen)
throw new ArtemisCoreException("Cannot update the texture while rendering");
- IManagedGraphicsContext? graphicsContext = Constants.ManagedGraphicsContext = _newGraphicsContext;
- if (!ReferenceEquals(graphicsContext, _newGraphicsContext))
- graphicsContext = _newGraphicsContext;
-
- if (graphicsContext != null)
- _logger.Debug("Creating SKTexture with graphics context {graphicsContext}", graphicsContext.GetType().Name);
- else
- _logger.Debug("Creating SKTexture with software-based graphics context");
-
- float evenWidth = Surface.Boundary.Size.Width;
- if (evenWidth % 2 != 0)
- evenWidth++;
- float evenHeight = Surface.Boundary.Size.Height;
- if (evenHeight % 2 != 0)
- evenHeight++;
-
- float renderScale = (float) _renderScaleSetting.Value;
- int width = Math.Max(1, MathF.Min(evenWidth * renderScale, 4096).RoundToInt());
- int height = Math.Max(1, MathF.Min(evenHeight * renderScale, 4096).RoundToInt());
-
- _texture?.Dispose();
- _texture = new SKTexture(graphicsContext, width, height, renderScale);
- _textureBrush.Texture = _texture;
-
-
- if (!ReferenceEquals(_newGraphicsContext, Constants.ManagedGraphicsContext = _newGraphicsContext))
+ lock (_devices)
{
- Constants.ManagedGraphicsContext?.Dispose();
- Constants.ManagedGraphicsContext = _newGraphicsContext;
- _newGraphicsContext = null;
+ IManagedGraphicsContext? graphicsContext = Constants.ManagedGraphicsContext = _newGraphicsContext;
+ if (!ReferenceEquals(graphicsContext, _newGraphicsContext))
+ graphicsContext = _newGraphicsContext;
+
+ if (graphicsContext != null)
+ _logger.Debug("Creating SKTexture with graphics context {graphicsContext}", graphicsContext.GetType().Name);
+ else
+ _logger.Debug("Creating SKTexture with software-based graphics context");
+
+ float evenWidth = Surface.Boundary.Size.Width;
+ if (evenWidth % 2 != 0)
+ evenWidth++;
+ float evenHeight = Surface.Boundary.Size.Height;
+ if (evenHeight % 2 != 0)
+ evenHeight++;
+
+ float renderScale = (float) _renderScaleSetting.Value;
+ int width = Math.Max(1, MathF.Min(evenWidth * renderScale, 4096).RoundToInt());
+ int height = Math.Max(1, MathF.Min(evenHeight * renderScale, 4096).RoundToInt());
+
+ _texture?.Dispose();
+ _texture = new SKTexture(graphicsContext, width, height, renderScale);
+ _textureBrush.Texture = _texture;
+
+
+ if (!ReferenceEquals(_newGraphicsContext, Constants.ManagedGraphicsContext = _newGraphicsContext))
+ {
+ Constants.ManagedGraphicsContext?.Dispose();
+ Constants.ManagedGraphicsContext = _newGraphicsContext;
+ _newGraphicsContext = null;
+ }
}
}
@@ -315,12 +338,22 @@ namespace Artemis.Core.Services
public void AutoArrangeDevices()
{
- SurfaceArrangement surfaceArrangement = SurfaceArrangement.GetDefaultArrangement();
- surfaceArrangement.Arrange(_devices);
- foreach (ArtemisDevice artemisDevice in _devices)
- artemisDevice.ApplyDefaultCategories();
+ bool changedRenderPaused = SetRenderPaused(true);
- SaveDevices();
+ try
+ {
+ SurfaceArrangement surfaceArrangement = SurfaceArrangement.GetDefaultArrangement();
+ surfaceArrangement.Arrange(_devices);
+ foreach (ArtemisDevice artemisDevice in _devices)
+ artemisDevice.ApplyDefaultCategories();
+
+ SaveDevices();
+ }
+ finally
+ {
+ if (changedRenderPaused)
+ SetRenderPaused(false);
+ }
}
public ArtemisLayout? ApplyBestDeviceLayout(ArtemisDevice device)
@@ -391,7 +424,7 @@ namespace Artemis.Core.Services
_deviceRepository.Save(device.DeviceEntity);
DeviceProvider deviceProvider = device.DeviceProvider;
-
+
// Feels bad but need to in order to get the initial LEDs back
_pluginManagementService.DisablePluginFeature(deviceProvider, false);
Thread.Sleep(500);
diff --git a/src/Artemis.Core/Utilities/Utilities.cs b/src/Artemis.Core/Utilities/Utilities.cs
index 8577185bc..c55b07c93 100644
--- a/src/Artemis.Core/Utilities/Utilities.cs
+++ b/src/Artemis.Core/Utilities/Utilities.cs
@@ -18,8 +18,8 @@ namespace Artemis.Core
public static void PrepareFirstLaunch()
{
CreateAccessibleDirectory(Constants.DataFolder);
- CreateAccessibleDirectory(Constants.DataFolder + "plugins");
- CreateAccessibleDirectory(Constants.DataFolder + "user layouts");
+ CreateAccessibleDirectory(Path.Combine(Constants.DataFolder ,"plugins"));
+ CreateAccessibleDirectory(Path.Combine(Constants.DataFolder ,"user layouts"));
}
///
diff --git a/src/Artemis.Core/packages.lock.json b/src/Artemis.Core/packages.lock.json
index 3f8b70e19..ea7b5f80c 100644
--- a/src/Artemis.Core/packages.lock.json
+++ b/src/Artemis.Core/packages.lock.json
@@ -81,14 +81,11 @@
},
"Serilog.Sinks.Console": {
"type": "Direct",
- "requested": "[3.1.1, )",
- "resolved": "3.1.1",
- "contentHash": "56mI5AqvyF/i/c2451nvV71kq370XOCE4Uu5qiaJ295sOhMb9q3BWwG7mWLOVSnmpWiq0SBT3SXfgRXGNP6vzA==",
+ "requested": "[4.0.0, )",
+ "resolved": "4.0.0",
+ "contentHash": "yJQit9sTJ4xGLKgCujqDJsaGqBNJwGB/H898z+xYlMG06twy4//6LLnSrsmpduZxcHIG4im7cv+JmXLzXz2EkQ==",
"dependencies": {
- "Serilog": "2.5.0",
- "System.Console": "4.3.0",
- "System.Runtime.InteropServices": "4.3.0",
- "System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
+ "Serilog": "2.10.0"
}
},
"Serilog.Sinks.Debug": {
@@ -102,21 +99,18 @@
},
"Serilog.Sinks.File": {
"type": "Direct",
- "requested": "[4.1.0, )",
- "resolved": "4.1.0",
- "contentHash": "U0b34w+ZikbqWEZ3ui7BdzxY/19zwrdhLtI3o6tfmLdD3oXxg7n2TZJjwCCTlKPgRuYic9CBWfrZevbb70mTaw==",
+ "requested": "[5.0.0, )",
+ "resolved": "5.0.0",
+ "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
"dependencies": {
- "Serilog": "2.5.0",
- "System.IO.FileSystem": "4.0.1",
- "System.Text.Encoding.Extensions": "4.0.11",
- "System.Threading.Timer": "4.0.1"
+ "Serilog": "2.10.0"
}
},
"SkiaSharp": {
"type": "Direct",
- "requested": "[2.80.2, )",
- "resolved": "2.80.2",
- "contentHash": "D25rzdCwh+3L+XyXqpNa+H/yiLJbE3/R3K/XexwHyQjGdzZvSufFW3oqf3En7hhqSIsxsJ8f5NEZ0J5W5wlGBg==",
+ "requested": "[2.80.3, )",
+ "resolved": "2.80.3",
+ "contentHash": "qX6tGNP3+MXNYe2pKm0PCRiJ/cx+LTeLaggwZifB7sUMXhECfKKKHJq45VqZKt37xQegnCCdf1jHXwmHeJQs5Q==",
"dependencies": {
"System.Memory": "4.5.3"
}
diff --git a/src/Artemis.Storage/StorageManager.cs b/src/Artemis.Storage/StorageManager.cs
index 267f86fea..93775b16d 100644
--- a/src/Artemis.Storage/StorageManager.cs
+++ b/src/Artemis.Storage/StorageManager.cs
@@ -19,11 +19,11 @@ namespace Artemis.Storage
if (_inUse)
throw new Exception("Storage is already in use, can't backup now.");
- string database = $"{dataFolder}\\database.db";
+ string database = Path.Combine(dataFolder, "database.db");
if (!File.Exists(database))
return;
- string backupFolder = $"{dataFolder}\\database backups";
+ string backupFolder = Path.Combine(dataFolder, "database backups");
Directory.CreateDirectory(backupFolder);
FileSystemInfo[] files = new DirectoryInfo(backupFolder).GetFileSystemInfos();
if (files.Length >= 5)
@@ -36,7 +36,7 @@ namespace Artemis.Storage
oldest.Delete();
}
- File.Copy(database, $"{backupFolder}\\database-{DateTime.Now:yyyy-dd-M--HH-mm-ss}.db");
+ File.Copy(database, Path.Combine(backupFolder, $"database-{DateTime.Now:yyyy-dd-M--HH-mm-ss}.db"));
}
///
@@ -51,7 +51,7 @@ namespace Artemis.Storage
try
{
_inUse = true;
- return new LiteRepository($"FileName={dataFolder}\\database.db");
+ return new LiteRepository($"FileName={Path.Combine(dataFolder, "database.db")}");
}
catch (LiteException e)
{
diff --git a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj
index 857718991..6d9dc0fe0 100644
--- a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj
+++ b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj
@@ -40,8 +40,8 @@
-
-
+
+
diff --git a/src/Artemis.UI.Shared/packages.lock.json b/src/Artemis.UI.Shared/packages.lock.json
index f83560583..3ed7085b2 100644
--- a/src/Artemis.UI.Shared/packages.lock.json
+++ b/src/Artemis.UI.Shared/packages.lock.json
@@ -60,21 +60,21 @@
},
"SkiaSharp": {
"type": "Direct",
- "requested": "[2.80.2, )",
- "resolved": "2.80.2",
- "contentHash": "D25rzdCwh+3L+XyXqpNa+H/yiLJbE3/R3K/XexwHyQjGdzZvSufFW3oqf3En7hhqSIsxsJ8f5NEZ0J5W5wlGBg==",
+ "requested": "[2.80.3, )",
+ "resolved": "2.80.3",
+ "contentHash": "qX6tGNP3+MXNYe2pKm0PCRiJ/cx+LTeLaggwZifB7sUMXhECfKKKHJq45VqZKt37xQegnCCdf1jHXwmHeJQs5Q==",
"dependencies": {
"System.Memory": "4.5.3"
}
},
"SkiaSharp.Views.WPF": {
"type": "Direct",
- "requested": "[2.80.2, )",
- "resolved": "2.80.2",
- "contentHash": "Fzo2+MNwHDh9Cob8sk7OO26kp3bhofjXMwlEK8IncF1ehu9hi3sH9iQDJrue9a88VEJJ+yyLISPUFcmXlGHSyQ==",
+ "requested": "[2.80.3, )",
+ "resolved": "2.80.3",
+ "contentHash": "oKUMm7WzFeoie6rW5nnwSGKZ94misyRsAc1wU6SEqgd6ssW17nyfohHxHuBHtmpLtIRwvjhfAu3cMLrpX/oNcw==",
"dependencies": {
- "SkiaSharp": "2.80.2",
- "SkiaSharp.Views.Desktop.Common": "2.80.2"
+ "SkiaSharp": "2.80.3",
+ "SkiaSharp.Views.Desktop.Common": "2.80.3"
}
},
"Stylet": {
@@ -378,13 +378,10 @@
},
"Serilog.Sinks.Console": {
"type": "Transitive",
- "resolved": "3.1.1",
- "contentHash": "56mI5AqvyF/i/c2451nvV71kq370XOCE4Uu5qiaJ295sOhMb9q3BWwG7mWLOVSnmpWiq0SBT3SXfgRXGNP6vzA==",
+ "resolved": "4.0.0",
+ "contentHash": "yJQit9sTJ4xGLKgCujqDJsaGqBNJwGB/H898z+xYlMG06twy4//6LLnSrsmpduZxcHIG4im7cv+JmXLzXz2EkQ==",
"dependencies": {
- "Serilog": "2.5.0",
- "System.Console": "4.3.0",
- "System.Runtime.InteropServices": "4.3.0",
- "System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
+ "Serilog": "2.10.0"
}
},
"Serilog.Sinks.Debug": {
@@ -397,21 +394,19 @@
},
"Serilog.Sinks.File": {
"type": "Transitive",
- "resolved": "4.1.0",
- "contentHash": "U0b34w+ZikbqWEZ3ui7BdzxY/19zwrdhLtI3o6tfmLdD3oXxg7n2TZJjwCCTlKPgRuYic9CBWfrZevbb70mTaw==",
+ "resolved": "5.0.0",
+ "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
"dependencies": {
- "Serilog": "2.5.0",
- "System.IO.FileSystem": "4.0.1",
- "System.Text.Encoding.Extensions": "4.0.11",
- "System.Threading.Timer": "4.0.1"
+ "Serilog": "2.10.0"
}
},
"SkiaSharp.Views.Desktop.Common": {
"type": "Transitive",
- "resolved": "2.80.2",
- "contentHash": "0vBvweMysgl1wgjuTQUhdJMD5z5nBjtYqmnHPeX+qHfkc336Wj2L3jEqwmGb0YP+RV47gFGz0EzMAW6szZch9w==",
+ "resolved": "2.80.3",
+ "contentHash": "CMQu9fr3BxGRsRryDC6lkYbYaSI2CI+RqisFX0WIdbOdbigUOLhqchmKIMb4EdFAZk13vk862qiE9v97iDZS7g==",
"dependencies": {
- "SkiaSharp": "2.80.2"
+ "SkiaSharp": "2.80.3",
+ "System.Drawing.Common": "4.5.1"
}
},
"System.AppContext": {
@@ -1309,10 +1304,10 @@
"Ninject.Extensions.ChildKernel": "3.3.0",
"Ninject.Extensions.Conventions": "3.3.0",
"Serilog": "2.10.0",
- "Serilog.Sinks.Console": "3.1.1",
+ "Serilog.Sinks.Console": "4.0.0",
"Serilog.Sinks.Debug": "2.0.0",
- "Serilog.Sinks.File": "4.1.0",
- "SkiaSharp": "2.80.2",
+ "Serilog.Sinks.File": "5.0.0",
+ "SkiaSharp": "2.80.3",
"System.Buffers": "4.5.1",
"System.IO.FileSystem.AccessControl": "5.0.0",
"System.Numerics.Vectors": "4.5.0",
diff --git a/src/Artemis.UI/ApplicationStateManager.cs b/src/Artemis.UI/ApplicationStateManager.cs
index 45dc2098c..d2ac6eb02 100644
--- a/src/Artemis.UI/ApplicationStateManager.cs
+++ b/src/Artemis.UI/ApplicationStateManager.cs
@@ -92,7 +92,10 @@ namespace Artemis.UI
using HttpClient client = new();
try
{
- HttpResponseMessage httpResponseMessage = client.Send(new HttpRequestMessage(HttpMethod.Post, url + "remote/bring-to-foreground"));
+ CancellationTokenSource cts = new();
+ cts.CancelAfter(2000);
+
+ HttpResponseMessage httpResponseMessage = client.Send(new HttpRequestMessage(HttpMethod.Post, url + "remote/bring-to-foreground"), cts.Token);
httpResponseMessage.EnsureSuccessStatusCode();
return true;
}
diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index c7a744e8a..4576072f0 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -138,7 +138,7 @@
-
+
@@ -153,8 +153,8 @@
-
-
+
+
diff --git a/src/Artemis.UI/Screens/Home/HomeView.xaml b/src/Artemis.UI/Screens/Home/HomeView.xaml
index ce8cd134b..142cd5d14 100644
--- a/src/Artemis.UI/Screens/Home/HomeView.xaml
+++ b/src/Artemis.UI/Screens/Home/HomeView.xaml
@@ -38,199 +38,193 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
-
-
+
+
-
+
- Have a chat
- Plugins
+
- If you need help, have some feedback or have any other questions feel free to contact us through any of the
- following channels.
+ Artemis is built up using plugins. This means devices, brushes, effects and modules (for supporting games!) can all be added via plugins.
+ Under Settings > Plugins you can find your currently installed plugins, these default plugins are created by Artemis developers.
+
+ We're also keeping track of a list of third-party plugins on our wiki.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Open Source
-
- This project is completely open source. If you like it and want to say thanks you could hit the GitHub Star button,
- I like numbers. You could even make plugins, there's a full documentation on the website
-
-
-
+
- Feel like you want to make a donation? It would be gratefully received. Click the button to donate via PayPal.
+ Want more plugins? You can find them on our wiki.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Have a chat
+
+ If you need help, have some feedback or have any other questions feel free to contact us through any of the
+ following channels.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open Source
+
+ This project is completely open source. If you like it and want to say thanks you could hit the GitHub Star button,
+ I like numbers. You could even make plugins, there's a full documentation on the website
+
+
+
+
+
+
+ Feel like you want to make a donation? It would be gratefully received. Click the button to donate via PayPal.
+
+
+
+
+
+
-
-
-
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs
index 40f94cf4e..f1b262dc6 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs
@@ -259,8 +259,14 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
public void ResetZoomAndPan()
{
+ if (!Devices.Any())
+ {
+ PanZoomViewModel.Reset();
+ return;
+ }
+
// Create a rect surrounding all devices
- SKRect rect = new SKRect(
+ SKRect rect = new(
Devices.Min(d => d.Rectangle.Left),
Devices.Min(d => d.Rectangle.Top),
Devices.Max(d => d.Rectangle.Right),
diff --git a/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs
index 244b7e448..6d2800bfa 100644
--- a/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs
@@ -140,7 +140,7 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
Device.GreenScale = GreenScale / 100f;
Device.BlueScale = BlueScale / 100f;
- _rgbService.Surface.Update(true);
+ _rgbService.FlushLeds = true;
}
public void BrowseCustomLayout(object sender, MouseEventArgs e)
diff --git a/src/Artemis.UI/Screens/Settings/SettingsTabsView.xaml b/src/Artemis.UI/Screens/Settings/SettingsTabsView.xaml
index 4b4908289..5c0c68c7a 100644
--- a/src/Artemis.UI/Screens/Settings/SettingsTabsView.xaml
+++ b/src/Artemis.UI/Screens/Settings/SettingsTabsView.xaml
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings"
xmlns:s="https://github.com/canton7/Stylet"
+ xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:SettingsTabsViewModel}">
@@ -16,18 +17,31 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Artemis.UI/Screens/Settings/SettingsTabsViewModel.cs b/src/Artemis.UI/Screens/Settings/SettingsTabsViewModel.cs
index b85fd4c8e..fd3cbb27c 100644
--- a/src/Artemis.UI/Screens/Settings/SettingsTabsViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/SettingsTabsViewModel.cs
@@ -2,18 +2,23 @@
using Artemis.UI.Screens.Settings.Tabs.Devices;
using Artemis.UI.Screens.Settings.Tabs.General;
using Artemis.UI.Screens.Settings.Tabs.Plugins;
+using Artemis.UI.Services;
using Stylet;
namespace Artemis.UI.Screens.Settings
{
public class SettingsTabsViewModel : Conductor.Collection.OneActive
{
+ private readonly IDebugService _debugService;
+
public SettingsTabsViewModel(
GeneralSettingsTabViewModel generalSettingsTabViewModel,
PluginSettingsTabViewModel pluginSettingsTabViewModel,
DeviceSettingsTabViewModel deviceSettingsTabViewModel,
- AboutTabViewModel aboutTabViewModel)
+ AboutTabViewModel aboutTabViewModel,
+ IDebugService debugService)
{
+ _debugService = debugService;
DisplayName = "Settings";
Items.Add(generalSettingsTabViewModel);
@@ -23,5 +28,10 @@ namespace Artemis.UI.Screens.Settings
ActiveItem = generalSettingsTabViewModel;
}
+
+ public void ShowDebugger()
+ {
+ _debugService.ShowDebugger();
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureViewModel.cs
index 97ca37389..542a24c5a 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureViewModel.cs
@@ -37,7 +37,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
public PluginFeatureInfo FeatureInfo { get; }
- public Exception LoadException => FeatureInfo.Instance?.LoadException;
+ public Exception LoadException => FeatureInfo.LoadException;
public bool ShowShield { get; }
@@ -81,7 +81,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
public async Task InstallPrerequisites()
{
if (FeatureInfo.Prerequisites.Any())
- await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List { FeatureInfo });
+ await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List {FeatureInfo});
}
public async Task RemovePrerequisites()
@@ -119,12 +119,19 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
private async Task UpdateEnabled(bool enable)
{
- if (IsEnabled == enable || FeatureInfo.Instance == null)
+ if (IsEnabled == enable)
{
NotifyOfPropertyChange(nameof(IsEnabled));
return;
}
+ if (FeatureInfo.Instance == null)
+ {
+ NotifyOfPropertyChange(nameof(IsEnabled));
+ _messageService.ShowMessage($"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.", "VIEW LOGS", ShowLogsFolder);
+ return;
+ }
+
if (enable)
{
Enabling = true;
@@ -144,7 +151,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
// Check if all prerequisites are met async
if (!FeatureInfo.ArePrerequisitesMet())
{
- await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List { FeatureInfo });
+ await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List {FeatureInfo});
if (!FeatureInfo.ArePrerequisitesMet())
{
NotifyOfPropertyChange(nameof(IsEnabled));
@@ -156,7 +163,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
catch (Exception e)
{
- _messageService.ShowMessage($"Failed to enable {FeatureInfo.Name}\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder);
+ _messageService.ShowMessage($"Failed to enable '{FeatureInfo.Name}'.\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder);
}
finally
{
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabView.xaml
index e0f0eba86..bbd48ac62 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabView.xaml
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabView.xaml
@@ -20,6 +20,7 @@
+
The list below shows all loaded plugins.
@@ -38,7 +39,17 @@
Margin="5 0"
Text="{Binding SearchPluginInput, Delay=300, UpdateSourceTrigger=PropertyChanged}" />
-
+
+
protected override void OnActivate()
{
- _rgbService.IsRenderPaused = true;
+ _rgbService.SetRenderPaused(true);
base.OnActivate();
}
///
protected override void OnDeactivate()
{
- _rgbService.IsRenderPaused = false;
+ _rgbService.SetRenderPaused(false);
base.OnDeactivate();
}
diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.xaml b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.xaml
index 249956841..d569d59d4 100644
--- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.xaml
+++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.xaml
@@ -63,9 +63,8 @@
-
-
+
+
-
+
SetAndNotify(ref _colorFirstLedOnly, value);
}
+ public double MaxTextureSize => 4096 / _settingsService.GetSetting("Core.RenderScale", 0.5).Value;
+ public double MaxTextureSizeIndicatorThickness => 2 / PanZoomViewModel.Zoom;
+
public void OpenHyperlink(object sender, RequestNavigateEventArgs e)
{
Core.Utilities.OpenUrl(e.Uri.AbsoluteUri);
@@ -155,7 +159,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
protected override void OnInitialActivate()
{
LoadWorkspaceSettings();
- SurfaceDeviceViewModels.AddRange(_rgbService.EnabledDevices.OrderBy(d => d.ZIndex).Select(d => new SurfaceDeviceViewModel(d, _rgbService)));
+ SurfaceDeviceViewModels.AddRange(_rgbService.EnabledDevices.OrderBy(d => d.ZIndex).Select(d => new SurfaceDeviceViewModel(d, _rgbService, _settingsService)));
ListDeviceViewModels.AddRange(_rgbService.EnabledDevices.OrderBy(d => d.ZIndex * -1).Select(d => new ListDeviceViewModel(d, this)));
List shuffledDevices = _rgbService.EnabledDevices.OrderBy(d => Guid.NewGuid()).ToList();
@@ -168,7 +172,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
}
_coreService.FrameRendering += CoreServiceOnFrameRendering;
-
+ PanZoomViewModel.PropertyChanged += PanZoomViewModelOnPropertyChanged;
base.OnInitialActivate();
}
@@ -179,10 +183,17 @@ namespace Artemis.UI.Screens.SurfaceEditor
ListDeviceViewModels.Clear();
_coreService.FrameRendering -= CoreServiceOnFrameRendering;
+ PanZoomViewModel.PropertyChanged -= PanZoomViewModelOnPropertyChanged;
base.OnClose();
}
+ private void PanZoomViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(PanZoomViewModel.Zoom))
+ NotifyOfPropertyChange(nameof(MaxTextureSizeIndicatorThickness));
+ }
+
#endregion
#region Context menu actions
@@ -322,7 +333,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
SurfaceDeviceViewModel device = HitTestUtilities.GetHitViewModels((Visual) sender, selectedRect).FirstOrDefault();
if (device != null)
{
- _rgbService.IsRenderPaused = true;
+ _rgbService.SetRenderPaused(true);
_mouseDragStatus = MouseDragStatus.Dragging;
// If the device is not selected, deselect others and select only this one (if shift not held)
if (device.SelectionStatus != SelectionStatus.Selected)
@@ -367,7 +378,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
}
_mouseDragStatus = MouseDragStatus.None;
- _rgbService.IsRenderPaused = false;
+ _rgbService.SetRenderPaused(false);
ApplySurfaceSelection();
}
diff --git a/src/Artemis.UI/Screens/SurfaceEditor/Visualization/SurfaceDeviceViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/Visualization/SurfaceDeviceViewModel.cs
index 50b3bcec1..82d14326c 100644
--- a/src/Artemis.UI/Screens/SurfaceEditor/Visualization/SurfaceDeviceViewModel.cs
+++ b/src/Artemis.UI/Screens/SurfaceEditor/Visualization/SurfaceDeviceViewModel.cs
@@ -14,15 +14,17 @@ namespace Artemis.UI.Screens.SurfaceEditor.Visualization
public class SurfaceDeviceViewModel : PropertyChangedBase
{
private readonly IRgbService _rgbService;
+ private readonly ISettingsService _settingsService;
private Cursor _cursor;
private double _dragOffsetX;
private double _dragOffsetY;
private SelectionStatus _selectionStatus;
- public SurfaceDeviceViewModel(ArtemisDevice device, IRgbService rgbService)
+ public SurfaceDeviceViewModel(ArtemisDevice device, IRgbService rgbService, ISettingsService settingsService)
{
Device = device;
_rgbService = rgbService;
+ _settingsService = settingsService;
}
public ArtemisDevice Device { get; }
@@ -101,6 +103,10 @@ namespace Artemis.UI.Screens.SurfaceEditor.Visualization
if (x < 0 || y < 0)
return false;
+ double maxTextureSize = 4096 / _settingsService.GetSetting("Core.RenderScale", 0.5).Value;
+ if (x + Device.Rectangle.Width > maxTextureSize || y + Device.Rectangle.Height > maxTextureSize)
+ return false;
+
List own = Device.Leds
.Select(l => SKRect.Create(l.Rectangle.Left + x, l.Rectangle.Top + y, l.Rectangle.Width, l.Rectangle.Height))
.ToList();
diff --git a/src/Artemis.UI/packages.lock.json b/src/Artemis.UI/packages.lock.json
index 2a76c380f..a82e9c086 100644
--- a/src/Artemis.UI/packages.lock.json
+++ b/src/Artemis.UI/packages.lock.json
@@ -4,9 +4,9 @@
".NETCoreApp,Version=v5.0": {
"FluentValidation": {
"type": "Direct",
- "requested": "[10.2.3, )",
- "resolved": "10.2.3",
- "contentHash": "R2w/E6jgg9RPSlg7JQSTHg6AWDwlOXARaV4ZUKrPJ1gi1e+oaBEcomxmo29j9BLZivkyQhOpAboJ9nKZS4/xYA=="
+ "requested": "[10.3.0, )",
+ "resolved": "10.3.0",
+ "contentHash": "ujEB9UMBPDLib6dyhSRhl93IE6ko4ZU6Nz9MFqohaKcvyf06Hk0yDQUFJGF6RgAOsm27O7ZZHVDpXx7oU5vBcg=="
},
"Flurl.Http": {
"type": "Direct",
@@ -130,22 +130,22 @@
},
"SkiaSharp.Views.WPF": {
"type": "Direct",
- "requested": "[2.80.2, )",
- "resolved": "2.80.2",
- "contentHash": "Fzo2+MNwHDh9Cob8sk7OO26kp3bhofjXMwlEK8IncF1ehu9hi3sH9iQDJrue9a88VEJJ+yyLISPUFcmXlGHSyQ==",
+ "requested": "[2.80.3, )",
+ "resolved": "2.80.3",
+ "contentHash": "oKUMm7WzFeoie6rW5nnwSGKZ94misyRsAc1wU6SEqgd6ssW17nyfohHxHuBHtmpLtIRwvjhfAu3cMLrpX/oNcw==",
"dependencies": {
- "SkiaSharp": "2.80.2",
- "SkiaSharp.Views.Desktop.Common": "2.80.2"
+ "SkiaSharp": "2.80.3",
+ "SkiaSharp.Views.Desktop.Common": "2.80.3"
}
},
"SkiaSharp.Vulkan.SharpVk": {
"type": "Direct",
- "requested": "[2.80.2, )",
- "resolved": "2.80.2",
- "contentHash": "qiqlbgMsSdxTsaPErtE1lXoMXolVVF9E6irmSTzlW++6BbW8tzA89n7GNsgMYJgyo2ljHZhX5ydhFn0Rkj7VHw==",
+ "requested": "[2.80.3, )",
+ "resolved": "2.80.3",
+ "contentHash": "IeR9oOHBsJUqpuVs23XgZXnrFV6WuOTaLpFhLVlXt2XILWIRrlrqx1PILgJm5bLqesceJLYZyMxVb/Ow7/uReA==",
"dependencies": {
"SharpVk": "0.4.2",
- "SkiaSharp": "2.80.2"
+ "SkiaSharp": "2.80.3"
}
},
"Stylet": {
@@ -491,13 +491,10 @@
},
"Serilog.Sinks.Console": {
"type": "Transitive",
- "resolved": "3.1.1",
- "contentHash": "56mI5AqvyF/i/c2451nvV71kq370XOCE4Uu5qiaJ295sOhMb9q3BWwG7mWLOVSnmpWiq0SBT3SXfgRXGNP6vzA==",
+ "resolved": "4.0.0",
+ "contentHash": "yJQit9sTJ4xGLKgCujqDJsaGqBNJwGB/H898z+xYlMG06twy4//6LLnSrsmpduZxcHIG4im7cv+JmXLzXz2EkQ==",
"dependencies": {
- "Serilog": "2.5.0",
- "System.Console": "4.3.0",
- "System.Runtime.InteropServices": "4.3.0",
- "System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
+ "Serilog": "2.10.0"
}
},
"Serilog.Sinks.Debug": {
@@ -510,13 +507,10 @@
},
"Serilog.Sinks.File": {
"type": "Transitive",
- "resolved": "4.1.0",
- "contentHash": "U0b34w+ZikbqWEZ3ui7BdzxY/19zwrdhLtI3o6tfmLdD3oXxg7n2TZJjwCCTlKPgRuYic9CBWfrZevbb70mTaw==",
+ "resolved": "5.0.0",
+ "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
"dependencies": {
- "Serilog": "2.5.0",
- "System.IO.FileSystem": "4.0.1",
- "System.Text.Encoding.Extensions": "4.0.11",
- "System.Threading.Timer": "4.0.1"
+ "Serilog": "2.10.0"
}
},
"SharpVectors.Reloaded": {
@@ -543,10 +537,11 @@
},
"SkiaSharp.Views.Desktop.Common": {
"type": "Transitive",
- "resolved": "2.80.2",
- "contentHash": "0vBvweMysgl1wgjuTQUhdJMD5z5nBjtYqmnHPeX+qHfkc336Wj2L3jEqwmGb0YP+RV47gFGz0EzMAW6szZch9w==",
+ "resolved": "2.80.3",
+ "contentHash": "CMQu9fr3BxGRsRryDC6lkYbYaSI2CI+RqisFX0WIdbOdbigUOLhqchmKIMb4EdFAZk13vk862qiE9v97iDZS7g==",
"dependencies": {
- "SkiaSharp": "2.80.2"
+ "SkiaSharp": "2.80.3",
+ "System.Drawing.Common": "4.5.1"
}
},
"System.AppContext": {
@@ -1442,10 +1437,10 @@
"Ninject.Extensions.ChildKernel": "3.3.0",
"Ninject.Extensions.Conventions": "3.3.0",
"Serilog": "2.10.0",
- "Serilog.Sinks.Console": "3.1.1",
+ "Serilog.Sinks.Console": "4.0.0",
"Serilog.Sinks.Debug": "2.0.0",
- "Serilog.Sinks.File": "4.1.0",
- "SkiaSharp": "2.80.2",
+ "Serilog.Sinks.File": "5.0.0",
+ "SkiaSharp": "2.80.3",
"System.Buffers": "4.5.1",
"System.IO.FileSystem.AccessControl": "5.0.0",
"System.Numerics.Vectors": "4.5.0",
@@ -1471,8 +1466,8 @@
"Ninject": "3.3.4",
"Ninject.Extensions.Conventions": "3.3.0",
"SharpVectors.Reloaded": "1.7.5",
- "SkiaSharp": "2.80.2",
- "SkiaSharp.Views.WPF": "2.80.2",
+ "SkiaSharp": "2.80.3",
+ "SkiaSharp.Views.WPF": "2.80.3",
"Stylet": "1.3.6",
"System.Buffers": "4.5.1",
"System.Numerics.Vectors": "4.5.0"