From d10ffcf62a5e290bec4afae8587a3b0f2ef566a7 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 11 Jul 2021 19:45:34 +0200 Subject: [PATCH 01/12] UI - Fix #640 --- .../ProfileEditor/Visualization/ProfileViewModel.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs index 6f4fea3d0..498eee76b 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs @@ -261,8 +261,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), From 0adcfa65c0d4c26cf9407b2e7077af8ef825d706 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Thu, 1 Jul 2021 15:50:19 +0100 Subject: [PATCH 02/12] Core - replaced hardcoded backslashes with Path.Combine --- src/Artemis.Core/Constants.cs | 2 +- .../Models/Surface/Layout/ArtemisLayout.cs | 28 +++++++++---------- .../Models/Surface/Layout/ArtemisLedLayout.cs | 3 +- src/Artemis.Core/Ninject/LoggerProvider.cs | 3 +- src/Artemis.Core/Utilities/Utilities.cs | 4 +-- src/Artemis.Storage/StorageManager.cs | 8 +++--- 6 files changed, 24 insertions(+), 24 deletions(-) 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/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.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) { From 83212bfa07ed41360c415db95b04343ea12b52be Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 15 Jul 2021 09:12:40 +0200 Subject: [PATCH 03/12] Meta - Updated nuget packages --- src/Artemis.ConsoleUI/packages.lock.json | 28 ++++----- src/Artemis.Core/Artemis.Core.csproj | 6 +- src/Artemis.Core/packages.lock.json | 28 ++++----- .../Artemis.UI.Shared.csproj | 4 +- src/Artemis.UI.Shared/packages.lock.json | 47 +++++++------- src/Artemis.UI/Artemis.UI.csproj | 6 +- src/Artemis.UI/packages.lock.json | 63 +++++++++---------- 7 files changed, 80 insertions(+), 102 deletions(-) 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 6e416d8dd..a8b6dd96c 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/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.UI.Shared/Artemis.UI.Shared.csproj b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj index 33e955e6c..aebafad56 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/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 372979bc4..409b3797d 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -137,7 +137,7 @@ - + @@ -152,8 +152,8 @@ - - + + diff --git a/src/Artemis.UI/packages.lock.json b/src/Artemis.UI/packages.lock.json index ef2b15f3e..a235de541 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": { @@ -486,13 +486,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": { @@ -505,13 +502,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": { @@ -530,18 +524,19 @@ }, "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" } }, "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": { @@ -1437,10 +1432,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", @@ -1466,8 +1461,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" From 4e8d0bf70b240a77839af50de57385dee0342ea8 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 18 Jul 2021 20:11:58 +0200 Subject: [PATCH 04/12] Plugins - Remove old code for renaming plugins from early versions --- src/Artemis.Core/Services/PluginManagementService.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs index 00a74d2a5..bcd647d9a 100644 --- a/src/Artemis.Core/Services/PluginManagementService.cs +++ b/src/Artemis.Core/Services/PluginManagementService.cs @@ -90,12 +90,7 @@ 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); if (match == null) From 66b16204412bfed643d6aaad62f2fe22dbad5bb5 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 22 Jul 2021 23:35:08 +0200 Subject: [PATCH 05/12] Plugins UI - Improved error reporting on exceptions during enable --- src/Artemis.Core/Plugins/PluginFeature.cs | 23 ++++------ src/Artemis.Core/Plugins/PluginFeatureInfo.cs | 10 +++++ .../Services/PluginManagementService.cs | 4 ++ .../Screens/Settings/SettingsTabsView.xaml | 42 ++++++++++++------- .../Screens/Settings/SettingsTabsViewModel.cs | 12 +++++- .../Tabs/Plugins/PluginFeatureViewModel.cs | 17 +++++--- 6 files changed, 72 insertions(+), 36 deletions(-) diff --git a/src/Artemis.Core/Plugins/PluginFeature.cs b/src/Artemis.Core/Plugins/PluginFeature.cs index 983f20438..ef3917ba0 100644 --- a/src/Artemis.Core/Plugins/PluginFeature.cs +++ b/src/Artemis.Core/Plugins/PluginFeature.cs @@ -11,7 +11,7 @@ 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,15 +37,6 @@ 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); - } - /// /// Gets the identifier of this plugin feature /// @@ -149,10 +140,10 @@ namespace Artemis.Core 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 +156,21 @@ namespace Artemis.Core if (!enableTask.Wait(TimeSpan.FromSeconds(15))) throw new ArtemisPluginException(Plugin, "Plugin load timeout"); - LoadException = null; + Info.LoadException = null; 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/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs index bcd647d9a..de01c754f 100644 --- a/src/Artemis.Core/Services/PluginManagementService.cs +++ b/src/Artemis.Core/Services/PluginManagementService.cs @@ -426,6 +426,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; } } @@ -613,6 +614,9 @@ namespace Artemis.Core.Services new ArtemisPluginException(pluginFeature.Plugin, $"Exception during SetEnabled(true) on {pluginFeature}", e), "Failed to enable plugin" ); + + if (!isAutoEnable) + throw; } finally { 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 { From 9179010e12bd42a9297f2b78be8516c5afec5026 Mon Sep 17 00:00:00 2001 From: Robert Date: Sat, 24 Jul 2021 20:42:33 +0200 Subject: [PATCH 06/12] Plugins - Added retry system when auto-enabling features --- src/Artemis.Core/Plugins/PluginFeature.cs | 8 +++- .../Services/PluginManagementService.cs | 38 ++++++++++++++++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/Artemis.Core/Plugins/PluginFeature.cs b/src/Artemis.Core/Plugins/PluginFeature.cs index ef3917ba0..149d42632 100644 --- a/src/Artemis.Core/Plugins/PluginFeature.cs +++ b/src/Artemis.Core/Plugins/PluginFeature.cs @@ -12,7 +12,7 @@ namespace Artemis.Core { private bool _isEnabled; - + /// /// Gets the plugin feature info related to this feature /// @@ -37,6 +37,8 @@ namespace Artemis.Core internal set => SetAndNotify(ref _isEnabled, value); } + internal int AutoEnableAttempts { get; set; } + /// /// Gets the identifier of this plugin feature /// @@ -137,6 +139,9 @@ namespace Artemis.Core try { + if (isAutoEnable) + AutoEnableAttempts++; + if (isAutoEnable && GetLockFileCreated()) { // Don't wrap existing lock exceptions, simply rethrow them @@ -157,6 +162,7 @@ namespace Artemis.Core throw new ArtemisPluginException(Plugin, "Plugin load timeout"); Info.LoadException = null; + AutoEnableAttempts = 0; OnEnabled(); } // If enable failed, put it back in a disabled state diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs index de01c754f..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,7 +91,7 @@ namespace Artemis.Core.Services using StreamReader reader = new(metaDataFileEntry.Open()); PluginInfo builtInPluginInfo = CoreJson.DeserializeObject(reader.ReadToEnd())!; string preferred = builtInPluginInfo.PreferredPluginDirectory; - + // Find the matching plugin in the plugin folder DirectoryInfo? match = pluginDirectory.EnumerateDirectories().FirstOrDefault(d => d.Name == preferred); if (match == null) @@ -610,13 +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 + ); - if (!isAutoEnable) + 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 { From c08aea88637a97588168502a1587dfa669537a0d Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Sat, 7 Aug 2021 22:30:25 +0100 Subject: [PATCH 07/12] ColorQuantizer - Added FindAllColorVariations method --- .../ColorQuantizer/ColorQuantizerService.cs | 180 ++++++++++++++---- .../Services/ColorQuantizer/ColorSwatch.cs | 40 ++++ .../Interfaces/IColorQuantizerService.cs | 8 + 3 files changed, 193 insertions(+), 35 deletions(-) create mode 100644 src/Artemis.Core/Services/ColorQuantizer/ColorSwatch.cs 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); } } From aace06b6cc95d3937d0eb92aed128e1f63f87943 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 13 Aug 2021 22:04:26 +0200 Subject: [PATCH 08/12] Core - Added better way to flush LEDs UI - Fixed a freeze when opening the device properties window of a device Core - Updated RGB.NET sampler call for API changes --- src/Artemis.Core/RGB.NET/SKTexture.cs | 4 +- src/Artemis.Core/Services/CoreService.cs | 8 ++- .../Services/Interfaces/IRgbService.cs | 5 ++ src/Artemis.Core/Services/RgbService.cs | 72 +++++++++++-------- .../Tabs/DevicePropertiesTabViewModel.cs | 2 +- 5 files changed, 57 insertions(+), 34 deletions(-) diff --git a/src/Artemis.Core/RGB.NET/SKTexture.cs b/src/Artemis.Core/RGB.NET/SKTexture.cs index 27a9f6d5b..6bb77132a 100644 --- a/src/Artemis.Core/RGB.NET/SKTexture.cs +++ b/src/Artemis.Core/RGB.NET/SKTexture.cs @@ -107,7 +107,7 @@ namespace Artemis.Core GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer); Span pixelData = stackalloc byte[DATA_PER_PIXEL]; - Sampler.SampleColor(new SamplerInfo(skRectI.Width, skRectI.Height, buffer), pixelData); + Sampler.Sample(new SamplerInfo(skRectI.Width, skRectI.Height, buffer), pixelData); return GetColor(pixelData); } @@ -119,7 +119,7 @@ namespace Artemis.Core GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer); Span pixelData = stackalloc byte[DATA_PER_PIXEL]; - Sampler.SampleColor(new SamplerInfo(skRectI.Width, skRectI.Height, buffer), pixelData); + Sampler.Sample(new SamplerInfo(skRectI.Width, skRectI.Height, buffer), pixelData); ArrayPool.Shared.Return(rent); diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index a9fc7a45e..9dee9fedb 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -13,7 +13,6 @@ using RGB.NET.Core; using Serilog; using Serilog.Events; using SkiaSharp; -using Module = Artemis.Core.Modules.Module; namespace Artemis.Core.Services { @@ -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(); diff --git a/src/Artemis.Core/Services/Interfaces/IRgbService.cs b/src/Artemis.Core/Services/Interfaces/IRgbService.cs index 10ec9fa1b..5420edb8f 100644 --- a/src/Artemis.Core/Services/Interfaces/IRgbService.cs +++ b/src/Artemis.Core/Services/Interfaces/IRgbService.cs @@ -41,6 +41,11 @@ namespace Artemis.Core.Services /// 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 /// diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs index feff46dc2..f43b1ccc1 100644 --- a/src/Artemis.Core/Services/RgbService.cs +++ b/src/Artemis.Core/Services/RgbService.cs @@ -53,7 +53,7 @@ namespace Artemis.Core.Services UpdateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value}; Surface.RegisterUpdateTrigger(UpdateTrigger); - + Utilities.ShutdownRequested += UtilitiesOnShutdownRequested; } @@ -137,8 +137,14 @@ 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) { + if (RenderOpen) + throw new ArtemisCoreException("Cannot add a device provider while rendering"); + lock (_devices) { try @@ -199,6 +205,9 @@ namespace Artemis.Core.Services public void RemoveDeviceProvider(IRGBDeviceProvider deviceProvider) { + if (RenderOpen) + throw new ArtemisCoreException("Cannot update the remove device provider while rendering"); + lock (_devices) { try @@ -267,36 +276,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; + } } } 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) From dfdc28760e0b369779a3b7c4a600574e07973eb7 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 13 Aug 2021 22:38:03 +0200 Subject: [PATCH 09/12] Surface editor - Contain devices to the max texture size Surface editor - Show a bounding box indicating the max texture size --- src/Artemis.Core/Services/RgbService.cs | 1 - .../Screens/SurfaceEditor/SurfaceEditorView.xaml | 15 +++++++++++---- .../SurfaceEditor/SurfaceEditorViewModel.cs | 15 +++++++++++++-- .../Visualization/SurfaceDeviceViewModel.cs | 8 +++++++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs index f43b1ccc1..da343b558 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; 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 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(); From 6a929cdcc05b256c398e9426d63b646acdd9ee76 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 20 Aug 2021 12:53:24 +0200 Subject: [PATCH 10/12] Home - Added plugins section Settings - Add link to plugins wiki page --- src/Artemis.UI/Screens/Home/HomeView.xaml | 312 +++++++++--------- .../Tabs/Plugins/PluginSettingsTabView.xaml | 13 +- .../Plugins/PluginSettingsTabViewModel.cs | 5 + 3 files changed, 170 insertions(+), 160 deletions(-) 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/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}" /> - + +