Browse Source

Enable/Disable mask

Equbuxu 3 years ago
parent
commit
8cc6a97c25

+ 5 - 0
src/PixiEditor.ChangeableDocument/ChangeInfos/Properties/StructureMemberMaskIsVisible_ChangeInfo.cs

@@ -0,0 +1,5 @@
+namespace PixiEditor.ChangeableDocument.ChangeInfos.Properties;
+public record class StructureMemberMaskIsVisible_ChangeInfo : IChangeInfo
+{
+    public Guid GuidValue { get; init; }
+}

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyStructureMember.cs

@@ -1,11 +1,11 @@
-using ChunkyImageLib;
-using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.ChangeableDocument.Enums;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Interfaces;
 
 public interface IReadOnlyStructureMember
 {
     bool IsVisible { get; }
+    bool MaskIsVisible { get; }
     bool ClipToMemberBelow { get; }
     string Name { get; }
     Guid GuidValue { get; }

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/StructureMember.cs

@@ -12,6 +12,7 @@ internal abstract class StructureMember : IChangeable, IReadOnlyStructureMember,
     public BlendMode BlendMode { get; set; } = BlendMode.Normal;
     public Guid GuidValue { get; init; }
     public ChunkyImage? Mask { get; set; } = null;
+    public bool MaskIsVisible { get; set; } = true;
     IReadOnlyChunkyImage? IReadOnlyStructureMember.Mask => Mask;
 
     internal abstract StructureMember Clone();

+ 47 - 0
src/PixiEditor.ChangeableDocument/Changes/Properties/StructureMemberMaskIsVisible_Change.cs

@@ -0,0 +1,47 @@
+using PixiEditor.ChangeableDocument.ChangeInfos.Properties;
+
+namespace PixiEditor.ChangeableDocument.Changes.Properties;
+internal class StructureMemberMaskIsVisible_Change : Change
+{
+    private readonly Guid memberGuid;
+    private bool originalMaskIsVisible;
+    private readonly bool newMaskIsVisible;
+
+    [GenerateMakeChangeAction]
+    public StructureMemberMaskIsVisible_Change(bool maskIsVisible, Guid memberGuid)
+    {
+        this.memberGuid = memberGuid;
+        this.newMaskIsVisible = maskIsVisible;
+    }
+
+    public override OneOf<Success, Error> InitializeAndValidate(Document target)
+    {
+        var member = target.FindMember(memberGuid);
+        if (member is null)
+            return new Error();
+        if (member.MaskIsVisible == newMaskIsVisible)
+            return new Error();
+        originalMaskIsVisible = member.MaskIsVisible;
+        return new Success();
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, out bool ignoreInUndo)
+    {
+        var member = target.FindMemberOrThrow(memberGuid);
+        member.MaskIsVisible = newMaskIsVisible;
+        ignoreInUndo = false;
+        return new StructureMemberMaskIsVisible_ChangeInfo() { GuidValue = memberGuid };
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
+    {
+        var member = target.FindMemberOrThrow(memberGuid);
+        member.MaskIsVisible = originalMaskIsVisible;
+        return new StructureMemberMaskIsVisible_ChangeInfo() { GuidValue = memberGuid };
+    }
+
+    public override bool IsMergeableWith(Change other)
+    {
+        return other is StructureMemberMaskIsVisible_Change change && change.memberGuid == memberGuid;
+    }
+}

+ 4 - 4
src/PixiEditor.ChangeableDocument/Rendering/ChunkRenderer.cs

@@ -61,7 +61,7 @@ public static class ChunkRenderer
         if (clippingChunk.IsT1 || !layer.IsVisible || layer.Opacity == 0)
             return new EmptyChunk();
 
-        if (layer.Mask is not null)
+        if (layer.Mask is not null && layer.MaskIsVisible)
             return RenderLayerWithMask(context, targetChunk, chunkPos, resolution, layer, clippingChunk);
 
         context.UpdateFromMember(layer);
@@ -83,7 +83,7 @@ public static class ChunkRenderer
     {
         if (clippingChunk.IsT1 || !layer.IsVisible || layer.Opacity == 0)
             return;
-        if (layer.Mask is not null)
+        if (layer.Mask is not null && layer.MaskIsVisible)
         {
             var result = RenderLayerWithMask(context, targetChunk, chunkPos, resolution, layer, clippingChunk);
             if (result.IsT1)
@@ -116,7 +116,7 @@ public static class ChunkRenderer
             !folder.IsVisible ||
             folder.Opacity == 0 ||
             folder.Children.Count == 0 ||
-            (folder.Mask is not null && !folder.Mask.LatestOrCommittedChunkExists(chunkPos))
+            (folder.Mask is not null && folder.MaskIsVisible && !folder.Mask.LatestOrCommittedChunkExists(chunkPos))
             )
             return new EmptyChunk();
 
@@ -125,7 +125,7 @@ public static class ChunkRenderer
             return new EmptyChunk();
         Chunk contents = maybeContents.AsT0;
 
-        if (folder.Mask is not null)
+        if (folder.Mask is not null && folder.MaskIsVisible)
         {
             if (!folder.Mask.DrawMostUpToDateChunkOn(chunkPos, resolution, contents.Surface.SkiaSurface, VecI.Zero, ClippingPaint))
             {

+ 9 - 0
src/PixiEditorPrototype/Models/DocumentUpdater.cs

@@ -80,9 +80,18 @@ internal class DocumentUpdater
             case StructureMemberClipToMemberBelow_ChangeInfo info:
                 ProcessClipToMemberBelow(info);
                 break;
+            case StructureMemberMaskIsVisible_ChangeInfo info:
+                ProcessMaskIsVisible(info);
+                break;
         }
     }
 
+    private void ProcessMaskIsVisible(StructureMemberMaskIsVisible_ChangeInfo info)
+    {
+        var member = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        member.RaisePropertyChanged(nameof(member.MaskIsVisible));
+    }
+
     private void ProcessClipToMemberBelow(StructureMemberClipToMemberBelow_ChangeInfo info)
     {
         var member = helper.StructureHelper.FindOrThrow(info.GuidValue);

+ 6 - 2
src/PixiEditorPrototype/Models/Rendering/AffectedChunkGatherer.cs

@@ -85,6 +85,10 @@ internal class AffectedChunkGatherer
                     AddAllToMainImage(info.GuidValue);
                     AddAllToImagePreviews(info.GuidValue, true);
                     break;
+                case StructureMemberMaskIsVisible_ChangeInfo info:
+                    AddAllToMainImage(info.GuidValue, false);
+                    AddAllToImagePreviews(info.GuidValue, true);
+                    break;
             }
         }
     }
@@ -102,13 +106,13 @@ internal class AffectedChunkGatherer
             AddWholeCanvasToImagePreviews(memberGuid, ignoreSelf);
         }
     }
-    private void AddAllToMainImage(Guid memberGuid)
+    private void AddAllToMainImage(Guid memberGuid, bool useMask = true)
     {
         var member = tracker.Document.FindMember(memberGuid);
         if (member is IReadOnlyLayer layer)
         {
             var chunks = layer.LayerImage.FindAllChunks();
-            if (layer.Mask is not null)
+            if (layer.Mask is not null && layer.MaskIsVisible && useMask)
                 chunks.IntersectWith(layer.Mask.FindAllChunks());
             AddToMainImage(chunks);
         }

+ 6 - 0
src/PixiEditorPrototype/ViewModels/StructureMemberViewModel.cs

@@ -30,6 +30,12 @@ internal abstract class StructureMemberViewModel : INotifyPropertyChanged
         set => Helpers.ActionAccumulator.AddFinishedActions(new StructureMemberIsVisible_Action(value, member.GuidValue));
     }
 
+    public bool MaskIsVisible
+    {
+        get => member.MaskIsVisible;
+        set => Helpers.ActionAccumulator.AddFinishedActions(new StructureMemberMaskIsVisible_Action(value, member.GuidValue));
+    }
+
     public BlendMode BlendMode
     {
         get => member.BlendMode;

+ 12 - 2
src/PixiEditorPrototype/Views/MainWindow.xaml

@@ -85,7 +85,12 @@
                     <TreeView.Resources>
                         <HierarchicalDataTemplate DataType="{x:Type vm:FolderViewModel}" ItemsSource="{Binding Children}">
                             <StackPanel Orientation="Horizontal" MinWidth="200" Background="Wheat">
-                                <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding IsVisible}"/>
+                                <StackPanel Orientation="Vertical" VerticalAlignment="Center">
+                                    <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding IsVisible}"/>
+                                    <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding MaskIsVisible}"
+                                              Visibility="{Binding HasMask, Converter={StaticResource BoolToVisibilityConverter}}"
+                                              Background="LightBlue"/>
+                                </StackPanel>
                                 <Rectangle 
                                     Fill="DarkRed" Width="8" Margin="3,0" 
                                     Visibility="{Binding ClipToMemberBelowEnabled, Converter={StaticResource BoolToVisibilityConverter}}"/>
@@ -124,7 +129,12 @@
                         </HierarchicalDataTemplate>
                         <DataTemplate DataType="{x:Type vm:LayerViewModel}">
                             <StackPanel Orientation="Horizontal">
-                                <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding IsVisible}"/>
+                                <StackPanel Orientation="Vertical" VerticalAlignment="Center">
+                                    <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding IsVisible}"/>
+                                    <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding MaskIsVisible}"
+                                              Visibility="{Binding HasMask, Converter={StaticResource BoolToVisibilityConverter}}"
+                                              Background="LightBlue"/>
+                                </StackPanel>
                                 <Rectangle 
                                     Fill="DarkRed" Width="8" Margin="3,0" 
                                     Visibility="{Binding ClipToMemberBelowEnabled, Converter={StaticResource BoolToVisibilityConverter}}"/>

+ 1 - 1
src/README.md

@@ -110,7 +110,7 @@ Decouples the state of a document from the UI.
         - [x] Clip to selection
         - [x] Lock transparency
         - [x] Create/Delete mask
-        - [ ] Enable/Disable mask
+        - [x] Enable/Disable mask
         - [x] Apply mask
 - ViewModel
     - [ ] Loading window when background thread is busy