diff --git a/src/Artemis.Core/MVVM/CorePropertyChanged.cs b/src/Artemis.Core/MVVM/CorePropertyChanged.cs index 8ab50083a..5e7b6b417 100644 --- a/src/Artemis.Core/MVVM/CorePropertyChanged.cs +++ b/src/Artemis.Core/MVVM/CorePropertyChanged.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System.Collections.Generic; +using System.ComponentModel; using System.Runtime.CompilerServices; using Artemis.Core.Properties; @@ -26,7 +27,7 @@ public abstract class CorePropertyChanged : INotifyPropertyChanged [MethodImpl(MethodImplOptions.AggressiveInlining)] protected bool RequiresUpdate(ref T storage, T value) { - return !Equals(storage, value); + return !EqualityComparer.Default.Equals(storage, value); } /// diff --git a/src/Artemis.Core/Plugins/LayerBrushes/PerLedLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrushes/PerLedLayerBrush.cs index e1623b3fc..f0ace6a43 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/PerLedLayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/PerLedLayerBrush.cs @@ -28,6 +28,8 @@ public abstract class PerLedLayerBrush : PropertiesLayerBrush where T : La /// The color the LED will receive public abstract SKColor GetColor(ArtemisLed led, SKPoint renderPoint); + private readonly SKPoint[] _points = new SKPoint[2]; + internal override void InternalRender(SKCanvas canvas, SKRect bounds, SKPaint paint) { // We don't want rotation on this canvas because that'll displace the LEDs, translations are applied to the points of each LED instead @@ -37,25 +39,21 @@ public abstract class PerLedLayerBrush : PropertiesLayerBrush where T : La using SKPath pointsPath = new(); foreach (ArtemisLed artemisLed in Layer.Leds) { - pointsPath.AddPoly(new[] - { - new SKPoint(0, 0), - new SKPoint(artemisLed.AbsoluteRectangle.Left - Layer.Bounds.Left, artemisLed.AbsoluteRectangle.Top - Layer.Bounds.Top) - }); + _points[0] = new SKPoint(0, 0); + _points[1] = new SKPoint(artemisLed.AbsoluteRectangle.Left - Layer.Bounds.Left, artemisLed.AbsoluteRectangle.Top - Layer.Bounds.Top); + pointsPath.AddPoly(_points); } // Apply the translation to the points of each LED instead if (Layer.General.TransformMode.CurrentValue == LayerTransformMode.Normal && SupportsTransformation) pointsPath.Transform(Layer.GetTransformMatrix(true, true, true, true).Invert()); - SKPoint[] points = pointsPath.Points; - TryOrBreak(() => { for (int index = 0; index < Layer.Leds.Count; index++) { ArtemisLed artemisLed = Layer.Leds[index]; - SKPoint renderPoint = points[index * 2 + 1]; + SKPoint renderPoint = pointsPath.GetPoint(index * 2 + 1); if (!float.IsFinite(renderPoint.X) || !float.IsFinite(renderPoint.Y)) continue; diff --git a/src/Artemis.Core/Stores/LogStore.cs b/src/Artemis.Core/Stores/LogStore.cs index de459357d..a4a3e66ed 100644 --- a/src/Artemis.Core/Stores/LogStore.cs +++ b/src/Artemis.Core/Stores/LogStore.cs @@ -10,12 +10,25 @@ namespace Artemis.Core; /// public static class LogStore { + private static readonly object _lock = new(); + private static readonly LinkedList LinkedList = new(); /// /// Gets a list containing the last 500 log events. /// - public static List Events => LinkedList.ToList(); + public static List Events + { + get + { + List events; + + lock (_lock) + events = LinkedList.ToList(); + + return events; + } + } /// /// Occurs when a new was received. @@ -24,9 +37,13 @@ public static class LogStore internal static void Emit(LogEvent logEvent) { - LinkedList.AddLast(logEvent); - while (LinkedList.Count > 500) - LinkedList.RemoveFirst(); + lock (_lock) + { + LinkedList.AddLast(logEvent); + while (LinkedList.Count > 500) + LinkedList.RemoveFirst(); + } + OnEventAdded(new LogEventEventArgs(logEvent)); } diff --git a/src/Artemis.UI/Screens/Debugger/Tabs/Logs/LogsDebugView.axaml.cs b/src/Artemis.UI/Screens/Debugger/Tabs/Logs/LogsDebugView.axaml.cs index 20bb00ff2..132d4606a 100644 --- a/src/Artemis.UI/Screens/Debugger/Tabs/Logs/LogsDebugView.axaml.cs +++ b/src/Artemis.UI/Screens/Debugger/Tabs/Logs/LogsDebugView.axaml.cs @@ -14,7 +14,7 @@ namespace Artemis.UI.Screens.Debugger.Logs; public class LogsDebugView : ReactiveUserControl { private int _lineCount; - private TextEditor _textEditor; + private TextEditor? _textEditor; public LogsDebugView() { @@ -31,7 +31,7 @@ public class LogsDebugView : ReactiveUserControl protected override void OnInitialized() { base.OnInitialized(); - Dispatcher.UIThread.Post(() => _textEditor.ScrollToEnd(), DispatcherPriority.ApplicationIdle); + Dispatcher.UIThread.Post(() => _textEditor?.ScrollToEnd(), DispatcherPriority.ApplicationIdle); } private void OnTextChanged(object? sender, EventArgs e) diff --git a/src/Artemis.UI/Screens/Debugger/Tabs/Logs/LogsDebugViewModel.cs b/src/Artemis.UI/Screens/Debugger/Tabs/Logs/LogsDebugViewModel.cs index ca067a392..c1860b01a 100644 --- a/src/Artemis.UI/Screens/Debugger/Tabs/Logs/LogsDebugViewModel.cs +++ b/src/Artemis.UI/Screens/Debugger/Tabs/Logs/LogsDebugViewModel.cs @@ -48,8 +48,11 @@ public class LogsDebugViewModel : ActivatableViewModelBase }); } - private void AddLogEvent(LogEvent logEvent) + private void AddLogEvent(LogEvent? logEvent) { + if (logEvent is null) + return; + using StringWriter writer = new(); _formatter.Format(logEvent, writer); string line = writer.ToString(); @@ -60,7 +63,7 @@ public class LogsDebugViewModel : ActivatableViewModelBase private void RemoveOldestLine() { - int firstNewLine = Document.Text.IndexOf('\n'); + int firstNewLine = Document.IndexOf('\n', 0, Document.TextLength); if (firstNewLine == -1) { //this should never happen. diff --git a/src/Artemis.UI/Screens/StartupWizard/StartupWizardViewModel.cs b/src/Artemis.UI/Screens/StartupWizard/StartupWizardViewModel.cs index e2a3e516a..72d296643 100644 --- a/src/Artemis.UI/Screens/StartupWizard/StartupWizardViewModel.cs +++ b/src/Artemis.UI/Screens/StartupWizard/StartupWizardViewModel.cs @@ -52,7 +52,7 @@ public class StartupWizardViewModel : DialogViewModelBase DeviceProviders = new ObservableCollection(pluginManagementService.GetAllPlugins() .Where(p => p.Info.IsCompatible && p.Features.Any(f => f.AlwaysEnabled && f.FeatureType.IsAssignableTo(typeof(DeviceProvider)))) .OrderBy(p => p.Info.Name) - .Select(p => settingsVmFactory.PluginViewModel(p, null))); + .Select(p => settingsVmFactory.PluginViewModel(p, ReactiveCommand.Create(() => new Unit())))); CurrentStep = 1; SetupButtons();