Browse Source

layer api wip

Krzysztof Krysiński 1 year ago
parent
commit
30a033151c

+ 2 - 2
src/PixiEditor.AvaloniaUI/ViewModels/Document/DocumentViewModel.Serialization.cs

@@ -114,7 +114,7 @@ internal partial class DocumentViewModel
     
     private static ImageLayer ToSerializable(IReadOnlyLayer layer, IReadOnlyDocument document)
     {
-        var result = document.GetLayerImage(layer.GuidValue);
+        var result = document.GetLayerRasterizedImage(layer.GuidValue);
 
         var tightBounds = document.GetChunkAlignedLayerBounds(layer.GuidValue);
         using var data = result?.DrawingSurface.Snapshot().Encode();
@@ -124,7 +124,7 @@ internal partial class DocumentViewModel
             Width = result?.Size.X ?? 0, Height = result?.Size.Y ?? 0, OffsetX = tightBounds?.X ?? 0, OffsetY = tightBounds?.Y ?? 0,
             Enabled = layer.IsVisible, BlendMode = (BlendMode)(int)layer.BlendMode, ImageBytes = bytes,
             ClipToMemberBelow = layer.ClipToMemberBelow, Name = layer.Name,
-            LockAlpha = layer.LockTransparency,
+            LockAlpha = layer is ITransparencyLockable { LockTransparency: true },
             Opacity = layer.Opacity, Mask = GetMask(layer.Mask, layer.MaskIsVisible)
         };
 

+ 3 - 2
src/PixiEditor.ChangeableDocument/ChangeInfos/Structure/CreateLayer_ChangeInfo.cs

@@ -1,4 +1,5 @@
-using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using PixiEditor.ChangeableDocument.Enums;
 
 namespace PixiEditor.ChangeableDocument.ChangeInfos.Structure;
 public record class CreateLayer_ChangeInfo : CreateStructureMember_ChangeInfo
@@ -34,7 +35,7 @@ public record class CreateLayer_ChangeInfo : CreateStructureMember_ChangeInfo
             layer.GuidValue,
             layer.Mask is not null,
             layer.MaskIsVisible,
-            layer.LockTransparency
+            layer is ITransparencyLockable { LockTransparency: true }
             );
     }
 }

+ 4 - 4
src/PixiEditor.ChangeableDocument/Changeables/Document.cs

@@ -44,7 +44,7 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
     /// <remarks>So yeah, welcome folks to the multithreaded world, where possibilities are endless! (and chances of objects getting
     /// edited, in between of processing you want to make exist). You might encounter ObjectDisposedException and other mighty creatures here if
     /// you are lucky enough. Have fun!</remarks>
-    public Surface? GetLayerImage(Guid layerGuid)
+    public Surface? GetLayerRasterizedImage(Guid layerGuid)
     {
         var layer = (IReadOnlyLayer?)FindMember(layerGuid);
 
@@ -52,7 +52,7 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
             throw new ArgumentException(@"The given guid does not belong to a layer.", nameof(layerGuid));
 
 
-        RectI? tightBounds = layer.LayerImage.FindChunkAlignedMostUpToDateBounds();
+        RectI? tightBounds = layer.GetTightBounds();
 
         if (tightBounds is null)
             return null;
@@ -61,7 +61,7 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
 
         Surface surface = new Surface(tightBounds.Value.Size);
 
-        layer.LayerImage.DrawMostUpToDateRegionOn(
+        layer.Rasterize().DrawMostUpToDateRegionOn(
             tightBounds.Value,
             ChunkResolution.Full,
             surface.DrawingSurface, VecI.Zero);
@@ -77,7 +77,7 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
             throw new ArgumentException(@"The given guid does not belong to a layer.", nameof(layerGuid));
 
 
-        return layer.LayerImage.FindChunkAlignedMostUpToDateBounds();
+        return layer.GetTightBounds();
     }
     
     public void ForEveryReadonlyMember(Action<IReadOnlyStructureMember> action) => ForEveryReadonlyMember(StructureRoot, action);

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyDocument.cs

@@ -45,7 +45,7 @@ public interface IReadOnlyDocument
     /// </summary>
     void ForEveryReadonlyMember(Action<IReadOnlyStructureMember> action);
     
-    public Surface? GetLayerImage(Guid layerGuid);
+    public Surface? GetLayerRasterizedImage(Guid layerGuid);
     public RectI? GetChunkAlignedLayerBounds(Guid layerGuid);
 
     /// <summary>

+ 5 - 9
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyLayer.cs

@@ -1,13 +1,9 @@
-namespace PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Changeables.Interfaces;
 
 public interface IReadOnlyLayer : IReadOnlyStructureMember
 {
-    /// <summary>
-    /// The chunky image of the layer
-    /// </summary>
-    IReadOnlyChunkyImage LayerImage { get; }
-    /// <summary>
-    /// Locks the transparency of the layer
-    /// </summary>
-    bool LockTransparency { get; }
+    public ChunkyImage Rasterize();
+    public RectI? GetTightBounds();
 }

+ 9 - 0
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyRasterLayer.cs

@@ -0,0 +1,9 @@
+namespace PixiEditor.ChangeableDocument.Changeables.Interfaces;
+
+public interface IReadOnlyRasterLayer : ITransparencyLockable
+{
+    /// <summary>
+    /// The chunky image of the layer
+    /// </summary>
+    IReadOnlyChunkyImage LayerImage { get; }
+}

+ 9 - 0
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/ITransparencyLockable.cs

@@ -0,0 +1,9 @@
+namespace PixiEditor.ChangeableDocument.Changeables.Interfaces;
+
+public interface ITransparencyLockable
+{
+    /// <summary>
+    /// Locks the transparency of the layer
+    /// </summary>
+    bool LockTransparency { get; set; }
+}

+ 3 - 43
src/PixiEditor.ChangeableDocument/Changeables/Layer.cs

@@ -3,48 +3,8 @@ using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changeables;
 
-internal class Layer : StructureMember, IReadOnlyLayer
+internal abstract class Layer : StructureMember, IReadOnlyLayer
 {
-    // Don't forget to update CreateLayer_ChangeInfo, DocumentUpdater.ProcessCreateStructureMember and Layer.Clone when adding new properties
-    public bool LockTransparency { get; set; } = false;
-    public ChunkyImage LayerImage { get; set; }
-    IReadOnlyChunkyImage IReadOnlyLayer.LayerImage => LayerImage;
-
-    public Layer(VecI size)
-    {
-        LayerImage = new(size);
-    }
-
-    public Layer(ChunkyImage image)
-    {
-        LayerImage = image;
-    }
-
-    /// <summary>
-    /// Disposes the layer's image and mask
-    /// </summary>
-    public override void Dispose()
-    {
-        LayerImage.Dispose();
-        Mask?.Dispose();
-    }
-
-    /// <summary>
-    /// Creates a clone of the layer, its image and its mask
-    /// </summary>
-    internal override Layer Clone()
-    {
-        return new Layer(LayerImage.CloneFromCommitted())
-        {
-            GuidValue = GuidValue,
-            IsVisible = IsVisible,
-            Name = Name,
-            Opacity = Opacity,
-            Mask = Mask?.CloneFromCommitted(),
-            ClipToMemberBelow = ClipToMemberBelow,
-            MaskIsVisible = MaskIsVisible,
-            BlendMode = BlendMode,
-            LockTransparency = LockTransparency
-        };
-    }
+    public abstract ChunkyImage Rasterize();
+    public abstract RectI? GetTightBounds();
 }

+ 60 - 0
src/PixiEditor.ChangeableDocument/Changeables/RasterLayer.cs

@@ -0,0 +1,60 @@
+using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Changeables;
+
+internal class RasterLayer : Layer, IReadOnlyRasterLayer
+{
+    // Don't forget to update CreateLayer_ChangeInfo, DocumentUpdater.ProcessCreateStructureMember and Layer.Clone when adding new properties
+    public bool LockTransparency { get; set; } = false;
+    public ChunkyImage LayerImage { get; set; }
+    IReadOnlyChunkyImage IReadOnlyRasterLayer.LayerImage => LayerImage;
+
+    public RasterLayer(VecI size)
+    {
+        LayerImage = new(size);
+    }
+
+    public RasterLayer(ChunkyImage image)
+    {
+        LayerImage = image;
+    }
+
+    /// <summary>
+    /// Disposes the layer's image and mask
+    /// </summary>
+    public override void Dispose()
+    {
+        LayerImage.Dispose();
+        Mask?.Dispose();
+    }
+
+    public override ChunkyImage Rasterize()
+    {
+        return LayerImage;
+    }
+
+    public override RectI? GetTightBounds()
+    {
+        return LayerImage.FindChunkAlignedMostUpToDateBounds();
+    }
+
+    /// <summary>
+    /// Creates a clone of the layer, its image and its mask
+    /// </summary>
+    internal override RasterLayer Clone()
+    {
+        return new RasterLayer(LayerImage.CloneFromCommitted())
+        {
+            GuidValue = GuidValue,
+            IsVisible = IsVisible,
+            Name = Name,
+            Opacity = Opacity,
+            Mask = Mask?.CloneFromCommitted(),
+            ClipToMemberBelow = ClipToMemberBelow,
+            MaskIsVisible = MaskIsVisible,
+            BlendMode = BlendMode,
+            LockTransparency = LockTransparency
+        };
+    }
+}

+ 3 - 2
src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawingChangeHelper.cs

@@ -1,4 +1,5 @@
-using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal static class DrawingChangeHelper
@@ -46,7 +47,7 @@ internal static class DrawingChangeHelper
             targetImage.SetClippingPath(target.Selection.SelectionPath);
 
         var targetMember = target.FindMemberOrThrow(targetMemberGuid);
-        if (targetMember is Layer { LockTransparency: true } && !drawOnMask)
+        if (targetMember is ITransparencyLockable { LockTransparency: true } && !drawOnMask)
             targetImage.EnableLockTransparency();
 
         if (target.HorizontalSymmetryAxisEnabled)

+ 8 - 4
src/PixiEditor.ChangeableDocument/Changes/Properties/LayerLockTransparency_Change.cs

@@ -1,4 +1,5 @@
-using PixiEditor.ChangeableDocument.ChangeInfos.Properties;
+using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using PixiEditor.ChangeableDocument.ChangeInfos.Properties;
 
 namespace PixiEditor.ChangeableDocument.Changes.Properties;
 internal class LayerLockTransparency_Change : Change
@@ -19,7 +20,10 @@ internal class LayerLockTransparency_Change : Change
         if (!target.TryFindMember<Layer>(layerGuid, out var layer))
             return false;
 
-        originalValue = layer.LockTransparency;
+        if (layer is not ITransparencyLockable lockable)
+               return false;
+
+        originalValue = lockable.LockTransparency;
         if (originalValue == newValue)
             return false;
         return true;
@@ -27,14 +31,14 @@ internal class LayerLockTransparency_Change : Change
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply, out bool ignoreInUndo)
     {
-        (target.FindMemberOrThrow<Layer>(layerGuid)).LockTransparency = newValue;
+        ((ITransparencyLockable)target.FindMemberOrThrow<Layer>(layerGuid)).LockTransparency = newValue;
         ignoreInUndo = false;
         return new LayerLockTransparency_ChangeInfo(layerGuid, newValue);
     }
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
     {
-        (target.FindMemberOrThrow<Layer>(layerGuid)).LockTransparency = originalValue;
+        ((ITransparencyLockable)target.FindMemberOrThrow<Layer>(layerGuid)).LockTransparency = originalValue;
         return new LayerLockTransparency_ChangeInfo(layerGuid, originalValue);
     }
 

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changes/Root/CenterContent_Change.cs

@@ -41,7 +41,7 @@ internal class CenterContent_Change : Change
         foreach (var layerGuid in affectedLayers)
         {
             Layer layer = document.FindMemberOrThrow<Layer>(layerGuid);
-            RectI? tightBounds = layer.LayerImage.FindTightCommittedBounds();
+            RectI? tightBounds = layer.GetTightBounds();
             if (tightBounds.HasValue)
             {
                 currentBounds = currentBounds.HasValue ? currentBounds.Value.Union(tightBounds.Value) : tightBounds;

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Structure/CreateStructureMember_Change.cs

@@ -31,7 +31,8 @@ internal class CreateStructureMember_Change : Change
 
         StructureMember member = type switch
         {
-            StructureMemberType.Layer => new Layer(document.Size) { GuidValue = newMemberGuid },
+            // TODO: Add support for other types
+            StructureMemberType.Layer => new RasterLayer(document.Size) { GuidValue = newMemberGuid },
             StructureMemberType.Folder => new Folder() { GuidValue = newMemberGuid },
             _ => throw new NotSupportedException(),
         };

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changes/Structure/DuplicateLayer_Change.cs

@@ -23,7 +23,7 @@ internal class DuplicateLayer_Change : Change
     {
         (Layer existingLayer, Folder parent) = ((Layer, Folder))target.FindChildAndParentOrThrow(layerGuid);
 
-        Layer clone = existingLayer.Clone();
+        Layer clone = (Layer)existingLayer.Clone();
         clone.GuidValue = duplicateGuid;
 
         int index = parent.Children.IndexOf(existingLayer);

+ 4 - 0
src/PixiEditor.Extensions.CommonApi/PixiEditor.Extensions.CommonApi.csproj

@@ -6,4 +6,8 @@
         <Nullable>disable</Nullable>
     </PropertyGroup>
 
+    <ItemGroup>
+      <ProjectReference Include="..\PixiEditor.DrawingApi.Core\PixiEditor.DrawingApi.Core.csproj" />
+    </ItemGroup>
+
 </Project>

+ 1 - 0
src/PixiEditor.Extensions/LayoutBuilding/Elements/StatefulElement.cs

@@ -33,6 +33,7 @@ public abstract class StatefulElement<TState> : LayoutElement, /*IPropertyDeseri
 
     public TState State => (TState)((IStatefulElement<Control>)this).State;
 
+    // TODO: Move actual Avalonia implementation to PixiEditor itself.
     public override Control BuildNative()
     {
         _presenter ??= new ContentPresenter();

+ 1 - 1
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.Serialization.cs

@@ -116,7 +116,7 @@ internal partial class DocumentViewModel
     
     private static ImageLayer ToSerializable(IReadOnlyLayer layer, IReadOnlyDocument document)
     {
-        var result = document.GetLayerImage(layer.GuidValue);
+        var result = document.GetLayerRasterizedImage(layer.GuidValue);
 
         var tightBounds = document.GetChunkAlignedLayerBounds(layer.GuidValue);
         using var data = result?.DrawingSurface.Snapshot().Encode();