diff --git a/src/Artemis.Core/Models/BreakableModel.cs b/src/Artemis.Core/Models/BreakableModel.cs index 1910cc2cc..f0338cd0f 100644 --- a/src/Artemis.Core/Models/BreakableModel.cs +++ b/src/Artemis.Core/Models/BreakableModel.cs @@ -59,7 +59,7 @@ public abstract class BreakableModel : CorePropertyChanged, IBreakableModel } /// - public void SetBrokenState(string state, Exception? exception) + public void SetBrokenState(string state, Exception? exception = null) { BrokenState = state ?? throw new ArgumentNullException(nameof(state)); BrokenStateException = exception; diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index a92aabc35..85683eb49 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -16,6 +16,9 @@ namespace Artemis.Core; /// public sealed class Layer : RenderProfileElement { + private const string BROKEN_STATE_BRUSH_NOT_FOUND = "Failed to load layer brush, ensure the plugin is enabled"; + private const string BROKEN_STATE_INIT_FAILED = "Failed to initialize layer brush"; + private readonly List _renderCopies = new(); private LayerGeneralProperties _general = new(); private LayerTransformProperties _transform = new(); @@ -261,7 +264,10 @@ public sealed class Layer : RenderProfileElement private void LayerBrushStoreOnLayerBrushRemoved(object? sender, LayerBrushStoreEvent e) { if (LayerBrush?.Descriptor == e.Registration.LayerBrushDescriptor) + { DeactivateLayerBrush(); + SetBrokenState(BROKEN_STATE_BRUSH_NOT_FOUND); + } } private void LayerBrushStoreOnLayerBrushAdded(object? sender, LayerBrushStoreEvent e) @@ -807,33 +813,46 @@ public sealed class Layer : RenderProfileElement /// /// Changes the current layer brush to the provided layer brush and activates it /// - public void ChangeLayerBrush(BaseLayerBrush? layerBrush) + public void ChangeLayerBrush(BaseLayerBrush layerBrush) { - BaseLayerBrush? oldLayerBrush = LayerBrush; + if (layerBrush == null) + throw new ArgumentNullException(nameof(layerBrush)); - General.BrushReference.SetCurrentValue(layerBrush != null ? new LayerBrushReference(layerBrush.Descriptor) : null); + BaseLayerBrush? oldLayerBrush = LayerBrush; + General.BrushReference.SetCurrentValue(new LayerBrushReference(layerBrush.Descriptor)); LayerBrush = layerBrush; + // Don't dispose the brush, only disable it + // That way an undo-action does not need to worry about disposed brushes oldLayerBrush?.InternalDisable(); - - if (LayerBrush != null) - ActivateLayerBrush(); - else - OnLayerBrushUpdated(); + ActivateLayerBrush(); } - internal void ActivateLayerBrush() + private void ActivateLayerBrush() { try { + // If the brush is null, try to instantiate it if (LayerBrush == null) { - // If the brush is null, try to instantiate it + // Ensure the provider is loaded and still provides the expected brush LayerBrushReference? brushReference = General.BrushReference.CurrentValue; if (brushReference?.LayerBrushProviderId != null && brushReference.BrushType != null) - ChangeLayerBrush(LayerBrushStore.Get(brushReference.LayerBrushProviderId, brushReference.BrushType)?.LayerBrushDescriptor.CreateInstance(this, LayerEntity.LayerBrush)); - // If that's not possible there's nothing to do - return; + { + // Only apply the brush if it is successfully retrieved from the store and instantiated + BaseLayerBrush? layerBrush = LayerBrushStore.Get(brushReference.LayerBrushProviderId, brushReference.BrushType)?.LayerBrushDescriptor.CreateInstance(this, LayerEntity.LayerBrush); + if (layerBrush != null) + { + ClearBrokenState(BROKEN_STATE_BRUSH_NOT_FOUND); + ChangeLayerBrush(layerBrush); + } + // If that's not possible there's nothing to do + else + { + SetBrokenState(BROKEN_STATE_BRUSH_NOT_FOUND); + return; + } + } } General.ShapeType.IsHidden = LayerBrush != null && !LayerBrush.SupportsTransformation; @@ -846,15 +865,15 @@ public sealed class Layer : RenderProfileElement } OnLayerBrushUpdated(); - ClearBrokenState("Failed to initialize layer brush"); + ClearBrokenState(BROKEN_STATE_INIT_FAILED); } catch (Exception e) { - SetBrokenState("Failed to initialize layer brush", e); + SetBrokenState(BROKEN_STATE_INIT_FAILED, e); } } - internal void DeactivateLayerBrush() + private void DeactivateLayerBrush() { if (LayerBrush == null) return; diff --git a/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ChangeLayerBrush.cs b/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ChangeLayerBrush.cs index 1c9a508c2..ce92133d6 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ChangeLayerBrush.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ChangeLayerBrush.cs @@ -54,7 +54,8 @@ public class ChangeLayerBrush : IProfileEditorCommand, IDisposable /// public void Undo() { - _layer.ChangeLayerBrush(_previousBrush); + if (_previousBrush != null) + _layer.ChangeLayerBrush(_previousBrush); _executed = false; } diff --git a/src/Artemis.UI.Shared/Styles/Artemis.axaml b/src/Artemis.UI.Shared/Styles/Artemis.axaml index 9907a4b20..988213ad4 100644 --- a/src/Artemis.UI.Shared/Styles/Artemis.axaml +++ b/src/Artemis.UI.Shared/Styles/Artemis.axaml @@ -21,6 +21,7 @@ + diff --git a/src/Artemis.UI.Shared/Styles/BrokenState.axaml b/src/Artemis.UI.Shared/Styles/BrokenState.axaml new file mode 100644 index 000000000..65ef465c0 --- /dev/null +++ b/src/Artemis.UI.Shared/Styles/BrokenState.axaml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml index b9301627e..60f0456da 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml @@ -4,21 +4,19 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:profileTree="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree" + xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.FolderTreeItemView" x:DataType="profileTree:FolderTreeItemViewModel"> - + - + - + + + -