mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 21:38:38 +00:00
Merge pull request #779 from Artemis-RGB/bugfix/layer-brush-null
Layers - Prevent brushes from going null when provider is missing
This commit is contained in:
commit
bee96166dd
@ -59,7 +59,7 @@ public abstract class BreakableModel : CorePropertyChanged, IBreakableModel
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetBrokenState(string state, Exception? exception)
|
||||
public void SetBrokenState(string state, Exception? exception = null)
|
||||
{
|
||||
BrokenState = state ?? throw new ArgumentNullException(nameof(state));
|
||||
BrokenStateException = exception;
|
||||
|
||||
@ -16,6 +16,9 @@ namespace Artemis.Core;
|
||||
/// </summary>
|
||||
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<Layer> _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
|
||||
/// <summary>
|
||||
/// Changes the current layer brush to the provided layer brush and activates it
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
@ -54,7 +54,8 @@ public class ChangeLayerBrush : IProfileEditorCommand, IDisposable
|
||||
/// <inheritdoc />
|
||||
public void Undo()
|
||||
{
|
||||
_layer.ChangeLayerBrush(_previousBrush);
|
||||
if (_previousBrush != null)
|
||||
_layer.ChangeLayerBrush(_previousBrush);
|
||||
_executed = false;
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
<!-- Custom styles -->
|
||||
<StyleInclude Source="/Styles/Border.axaml" />
|
||||
<StyleInclude Source="/Styles/BrokenState.axaml" />
|
||||
<StyleInclude Source="/Styles/Skeleton.axaml" />
|
||||
<StyleInclude Source="/Styles/Button.axaml" />
|
||||
<StyleInclude Source="/Styles/Condensed.axaml" />
|
||||
|
||||
20
src/Artemis.UI.Shared/Styles/BrokenState.axaml
Normal file
20
src/Artemis.UI.Shared/Styles/BrokenState.axaml
Normal file
@ -0,0 +1,20 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia">
|
||||
<Design.PreviewWith>
|
||||
|
||||
<controls:HyperlinkButton Grid.Column="0" Classes="icon-button icon-button-small broken-state-button" Margin="50">
|
||||
<avalonia:MaterialIcon Kind="AlertCircle" />
|
||||
</controls:HyperlinkButton>
|
||||
</Design.PreviewWith>
|
||||
|
||||
<!-- Add Styles Here -->
|
||||
<Style Selector="controls|HyperlinkButton.broken-state-button avalonia|MaterialIcon">
|
||||
<Setter Property="Foreground" Value="#E74C4C" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="controls|HyperlinkButton.broken-state-button:pointerover avalonia|MaterialIcon">
|
||||
<Setter Property="Foreground" Value="#B93F3F" />
|
||||
</Style>
|
||||
</Styles>
|
||||
@ -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">
|
||||
<Grid ColumnDefinitions="Auto,Auto,*,Auto,Auto">
|
||||
<Button Grid.Column="0"
|
||||
ToolTip.Tip="{CompiledBinding ProfileElement.BrokenState}"
|
||||
IsVisible="{CompiledBinding ProfileElement.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
Classes="icon-button icon-button-small"
|
||||
Foreground="White"
|
||||
Background="#E74C4C"
|
||||
BorderBrush="#E74C4C"
|
||||
Margin="0 0 5 0"
|
||||
Command="{Binding ShowBrokenStateExceptions}">
|
||||
<controls:HyperlinkButton Grid.Column="0"
|
||||
Classes="icon-button icon-button-small broken-state-button"
|
||||
Margin="0 0 5 0"
|
||||
Command="{CompiledBinding ShowBrokenStateExceptions}"
|
||||
IsVisible="{CompiledBinding ProfileElement.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
ToolTip.Tip="{CompiledBinding ProfileElement.BrokenState, FallbackValue=''}">
|
||||
<avalonia:MaterialIcon Kind="AlertCircle" />
|
||||
</Button>
|
||||
</controls:HyperlinkButton>
|
||||
<avalonia:MaterialIcon Grid.Column="1"
|
||||
Kind="Folder"
|
||||
Margin="0 0 5 0"
|
||||
|
||||
@ -4,19 +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.LayerTreeItemView"
|
||||
x:DataType="profileTree:LayerTreeItemViewModel">
|
||||
<Grid ColumnDefinitions="Auto,Auto,*,Auto,Auto">
|
||||
<Button Grid.Column="0"
|
||||
ToolTip.Tip="{CompiledBinding ProfileElement.BrokenState}"
|
||||
IsVisible="{CompiledBinding ProfileElement.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
Classes="icon-button icon-button-small"
|
||||
Foreground="#E74C4C"
|
||||
Margin="0 0 5 0"
|
||||
Command="{Binding ShowBrokenStateExceptions}">
|
||||
<controls:HyperlinkButton Grid.Column="0"
|
||||
Classes="icon-button icon-button-small broken-state-button"
|
||||
Margin="0 0 5 0"
|
||||
Command="{CompiledBinding ShowBrokenStateExceptions}"
|
||||
IsVisible="{CompiledBinding ProfileElement.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
ToolTip.Tip="{CompiledBinding ProfileElement.BrokenState, FallbackValue=''}">
|
||||
<avalonia:MaterialIcon Kind="AlertCircle" />
|
||||
</Button>
|
||||
</controls:HyperlinkButton>
|
||||
<avalonia:MaterialIcon Grid.Column="1" Kind="{CompiledBinding Layer.LayerBrush.Descriptor.Icon, FallbackValue=Layers}" Margin="0 0 5 0" />
|
||||
<TextBox Grid.Column="2"
|
||||
Margin="-5 0 0 0"
|
||||
|
||||
@ -39,21 +39,16 @@
|
||||
Background="{DynamicResource ContentDialogBackground}">
|
||||
<Border Background="{DynamicResource TaskDialogHeaderBackground}">
|
||||
<Grid Classes="node-header" VerticalAlignment="Top" ColumnDefinitions="Auto,*,Auto,Auto">
|
||||
<Button Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{CompiledBinding Node.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
Classes="icon-button icon-button-small"
|
||||
Foreground="White"
|
||||
Background="#E74C4C"
|
||||
BorderBrush="#E74C4C"
|
||||
Margin="5 0 0 0"
|
||||
ToolTip.Tip="{CompiledBinding Node.BrokenState}"
|
||||
Command="{CompiledBinding ShowBrokenState}">
|
||||
<avalonia:MaterialIcon Kind="AlertCircle"></avalonia:MaterialIcon>
|
||||
</Button>
|
||||
<controls:HyperlinkButton Grid.Column="0"
|
||||
Classes="icon-button icon-button-small broken-state-button"
|
||||
Margin="5 0 0 0"
|
||||
Command="{CompiledBinding ShowBrokenState}"
|
||||
IsVisible="{CompiledBinding Node.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
ToolTip.Tip="{CompiledBinding Node.BrokenState}">
|
||||
<avalonia:MaterialIcon Kind="AlertCircle" />
|
||||
</controls:HyperlinkButton>
|
||||
|
||||
<TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="10 0 0 0" Text="{CompiledBinding Node.Name}" ToolTip.Tip="{CompiledBinding Node.Description}" />
|
||||
|
||||
|
||||
<controls:HyperlinkButton Grid.Column="2"
|
||||
IsVisible="{CompiledBinding Node.HelpUrl, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user