From 4034f438edca95cc86dfb818b34cd0a6e5ec8c02 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 6 Jul 2021 23:45:34 +0200 Subject: [PATCH] UI - Fix possible exception when showing dialogs Profile editor - Limit undo/redo to 20 actions for now Plugins - Fix custom icons not displaying in settings windows --- src/Artemis.Core/Models/Profile/Profile.cs | 8 +- .../Services/Storage/ProfileService.cs | 4 +- src/Artemis.Core/Utilities/MaxStack.cs | 118 ++++++++++++++++++ .../Services/Dialog/DialogService.cs | 2 +- .../Plugins/PluginSettingsWindowView.xaml | 9 +- .../Plugins/PluginSettingsWindowViewModel.cs | 5 +- .../Services/DeviceLayoutService.cs | 10 +- 7 files changed, 143 insertions(+), 13 deletions(-) create mode 100644 src/Artemis.Core/Utilities/MaxStack.cs diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs index e2870dec1..a018b947a 100644 --- a/src/Artemis.Core/Models/Profile/Profile.cs +++ b/src/Artemis.Core/Models/Profile/Profile.cs @@ -25,8 +25,8 @@ namespace Artemis.Core Scripts = new List(); ScriptConfigurations = new List(); - UndoStack = new Stack(); - RedoStack = new Stack(); + UndoStack = new MaxStack(20); + RedoStack = new MaxStack(20); Load(); } @@ -75,8 +75,8 @@ namespace Artemis.Core /// public ProfileEntity ProfileEntity { get; internal set; } - internal Stack UndoStack { get; set; } - internal Stack RedoStack { get; set; } + internal MaxStack UndoStack { get; set; } + internal MaxStack RedoStack { get; set; } /// public override void Update(double deltaTime) diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index 5cdf00f06..63d17ee67 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -470,7 +470,7 @@ namespace Artemis.Core.Services // Keep the profile from being rendered by locking it lock (profile) { - if (!profile.UndoStack.Any()) + if (profile.UndoStack.Count == 0) { _logger.Debug("Undo profile update - Failed, undo stack empty"); return false; @@ -496,7 +496,7 @@ namespace Artemis.Core.Services // Keep the profile from being rendered by locking it lock (profile) { - if (!profile.RedoStack.Any()) + if (profile.RedoStack.Count == 0) { _logger.Debug("Redo profile update - Failed, redo empty"); return false; diff --git a/src/Artemis.Core/Utilities/MaxStack.cs b/src/Artemis.Core/Utilities/MaxStack.cs new file mode 100644 index 000000000..8767522d2 --- /dev/null +++ b/src/Artemis.Core/Utilities/MaxStack.cs @@ -0,0 +1,118 @@ +// Source: https://ntsblog.homedev.com.au/index.php/2010/05/06/c-stack-with-maximum-limit/ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Artemis.Core +{ + /// + /// Generic stack implementation with a maximum limit + /// When something is pushed on the last item is removed from the list + /// + [Serializable] + internal class MaxStack + { + #region Fields + + private int _limit; + private LinkedList _list; + + #endregion + + #region Constructors + + public MaxStack(int maxSize) + { + _limit = maxSize; + _list = new LinkedList(); + + } + + #endregion + + #region Public Stack Implementation + + public void Push(T value) + { + if (_list.Count == _limit) + { + _list.RemoveLast(); + } + _list.AddFirst(value); + } + + public T Pop() + { + if (_list.Count > 0) + { + T value = _list.First.Value; + _list.RemoveFirst(); + return value; + } + else + { + throw new InvalidOperationException("The Stack is empty"); + } + + + } + + public T Peek() + { + if (_list.Count > 0) + { + T value = _list.First.Value; + return value; + } + else + { + throw new InvalidOperationException("The Stack is empty"); + } + + } + + public void Clear() + { + _list.Clear(); + + } + + public int Count + { + get { return _list.Count; } + } + + /// + /// Checks if the top object on the stack matches the value passed in + /// + /// + /// + public bool IsTop(T value) + { + bool result = false; + if (this.Count > 0) + { + result = Peek().Equals(value); + } + return result; + } + + public bool Contains(T value) + { + bool result = false; + if (this.Count > 0) + { + result = _list.Contains(value); + } + return result; + } + + public IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + #endregion + + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs b/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs index e3d26e577..dcfe3b9d6 100644 --- a/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs +++ b/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs @@ -122,7 +122,7 @@ namespace Artemis.UI.Shared.Services public void ShowExceptionDialog(string message, Exception exception) { if (exception == null) throw new ArgumentNullException(nameof(exception)); - _windowManager.ShowDialog(new ExceptionViewModel(message, exception)); + Execute.OnUIThread(() => _windowManager.ShowDialog(new ExceptionViewModel(message, exception))); } private IKernel GetBestKernel() diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml index ad7623595..1500833d6 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml @@ -26,7 +26,14 @@ - + diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs index 47230b878..748713f48 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs @@ -1,4 +1,5 @@ using System; +using Artemis.Core; using Artemis.UI.Shared; using Stylet; @@ -11,10 +12,10 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins public PluginSettingsWindowViewModel(PluginConfigurationViewModel configurationViewModel) { _configurationViewModel = configurationViewModel ?? throw new ArgumentNullException(nameof(configurationViewModel)); - Icon = configurationViewModel.Plugin.Info.Icon; + Plugin = configurationViewModel.Plugin; } - public object Icon { get; } + public Plugin Plugin { get; } protected override void OnInitialActivate() { diff --git a/src/Artemis.UI/Services/DeviceLayoutService.cs b/src/Artemis.UI/Services/DeviceLayoutService.cs index 536763729..f15dcaca8 100644 --- a/src/Artemis.UI/Services/DeviceLayoutService.cs +++ b/src/Artemis.UI/Services/DeviceLayoutService.cs @@ -8,6 +8,7 @@ using Artemis.UI.Screens.Settings.Device; using Artemis.UI.Shared.Services; using MaterialDesignThemes.Wpf; using RGB.NET.Core; +using Stylet; using KeyboardLayoutType = Artemis.Core.KeyboardLayoutType; namespace Artemis.UI.Services @@ -62,8 +63,11 @@ namespace Artemis.UI.Services private async void WindowServiceOnMainWindowOpened(object sender, EventArgs e) { List devices = _rgbService.Devices.Where(device => DeviceNeedsLayout(device) && !_ignoredDevices.Contains(device)).ToList(); - foreach (ArtemisDevice artemisDevice in devices) - await RequestLayoutInput(artemisDevice); + await Execute.OnUIThreadAsync(async () => + { + foreach (ArtemisDevice artemisDevice in devices) + await RequestLayoutInput(artemisDevice); + }); } private async void RgbServiceOnDeviceAdded(object sender, DeviceEventArgs e) @@ -77,7 +81,7 @@ namespace Artemis.UI.Services return; } - await RequestLayoutInput(e.Device); + await Execute.OnUIThreadAsync(async () => await RequestLayoutInput(e.Device)); } #endregion