瀏覽代碼

Multi element selection is now working properly

flabbet 1 年之前
父節點
當前提交
aad0a8e7d3

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

@@ -76,7 +76,7 @@ internal class Document : IChangeable, IReadOnlyDocument
             throw new ArgumentException(@"The given guid does not belong to a layer.", nameof(layerGuid));
 
 
-        RectI? tightBounds = layer.GetTightBounds(frame);
+        RectI? tightBounds = (RectI)layer.GetTightBounds(frame);
 
         if (tightBounds is null)
             return null;
@@ -126,7 +126,7 @@ internal class Document : IChangeable, IReadOnlyDocument
             throw new ArgumentException(@"The given guid does not belong to a layer.", nameof(layerGuid));
 
 
-        return layer.GetTightBounds(frame);
+        return (RectI)layer.GetTightBounds(frame);
     }
 
     public void ForEveryReadonlyMember(Action<IReadOnlyStructureNode> action) =>

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Interfaces/IReadOnlyStructureNode.cs

@@ -14,7 +14,7 @@ public interface IReadOnlyStructureNode : IReadOnlyNode
     public InputProperty<Texture?> CustomMask { get; }
     public InputProperty<bool> MaskIsVisible { get; }
     public string MemberName { get; set; }
-    public RectI? GetTightBounds(KeyFrameTime frameTime);
+    public RectD? GetTightBounds(KeyFrameTime frameTime);
     public ChunkyImage? EmbeddedMask { get; }
     public ShapeCorners GetTransformationCorners(KeyFrameTime frameTime);
 }

+ 4 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FolderNode.cs

@@ -102,7 +102,7 @@ public class FolderNode : StructureNode, IReadOnlyFolderNode
         return Output.Value;
     }
 
-    public override RectI? GetTightBounds(KeyFrameTime frameTime)
+    public override RectD? GetTightBounds(KeyFrameTime frameTime)
     {
         RectI bounds = new RectI();
         if(Content.Connection != null)
@@ -111,7 +111,7 @@ public class FolderNode : StructureNode, IReadOnlyFolderNode
             {
                 if (n is ImageLayerNode imageLayerNode)
                 {
-                    RectI? imageBounds = imageLayerNode.GetTightBounds(frameTime);
+                    RectI? imageBounds = (RectI)imageLayerNode.GetTightBounds(frameTime);
                     if (imageBounds != null)
                     {
                         bounds = bounds.Union(imageBounds.Value);
@@ -121,10 +121,10 @@ public class FolderNode : StructureNode, IReadOnlyFolderNode
                 return true;
             });
             
-            return bounds;
+            return (RectD)bounds;
         }
         
-        return RectI.Create(0, 0, Content.Value?.Size.X ?? 0, Content.Value?.Size.Y ?? 0);
+        return (RectD)RectI.Create(0, 0, Content.Value?.Size.X ?? 0, Content.Value?.Size.Y ?? 0);
     }
 
     public HashSet<Guid> GetLayerNodeGuids()

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -51,9 +51,9 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         this.size = size;
     }
 
-    public override RectI? GetTightBounds(KeyFrameTime frameTime)
+    public override RectD? GetTightBounds(KeyFrameTime frameTime)
     {
-        return GetLayerImageAtFrame(frameTime.Frame).FindTightCommittedBounds();
+        return (RectD)GetLayerImageAtFrame(frameTime.Frame).FindTightCommittedBounds();
     }
 
     protected override Texture? OnExecute(RenderingContext context)

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/StructureNode.cs

@@ -167,7 +167,7 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
         return new RectI(x, y, width, height);
     }
 
-    public abstract RectI? GetTightBounds(KeyFrameTime frameTime);
+    public abstract RectD? GetTightBounds(KeyFrameTime frameTime);
 
     public override void Dispose()
     {

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/VectorLayerNode.cs

@@ -43,9 +43,9 @@ public class VectorLayerNode : LayerNode, ITransformableObject
         lastCacheHash = ShapeData.GetCacheHash();
     }
 
-    public override RectI? GetTightBounds(KeyFrameTime frameTime)
+    public override RectD? GetTightBounds(KeyFrameTime frameTime)
     {
-        return (RectI)ShapeData.TransformedAABB;
+        return ShapeData.TransformedAABB;
     }
 
     public override ShapeCorners GetTransformationCorners(KeyFrameTime frameTime)

+ 54 - 45
src/PixiEditor.ChangeableDocument/Changes/Drawing/TransformSelected_UpdateableChange.cs

@@ -22,15 +22,16 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
 
     private VectorPath? originalPath;
     private RectD originalSelectionBounds;
-    private VecD originalSize;
+    private VecD selectionAwareSize;
+    private VecD tightBoundsSize;
+    private RectD cornersToSelectionOffset;
+    private VecD originalCornersSize;
 
     private bool isTransformingSelection;
     private bool hasEnqueudImages = false;
     private int frame;
     private bool appliedOnce;
 
-    private Matrix3X3 globalMatrix;
-
     private static Paint RegularPaint { get; } = new() { BlendMode = BlendMode.SrcOver };
 
     [GenerateUpdateableChangeActions]
@@ -57,45 +58,48 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
     {
         if (memberData.Count == 0)
             return false;
-
-        RectD originalTightBounds = default;
+        
+        originalCornersSize = masterCorners.RectSize;
+        RectD tightBoundsWithSelection = default;
         bool hasSelection = target.Selection.SelectionPath is { IsEmpty: false };
 
         if (hasSelection)
         {
             originalPath = new VectorPath(target.Selection.SelectionPath) { FillType = PathFillType.EvenOdd };
-            originalTightBounds = originalPath.TightBounds;
-            originalSelectionBounds = originalTightBounds;
-            originalSize = originalTightBounds.Size;
+            tightBoundsWithSelection = originalPath.TightBounds;
+            originalSelectionBounds = tightBoundsWithSelection;
+            selectionAwareSize = tightBoundsWithSelection.Size;
             isTransformingSelection = true;
+            
+            tightBoundsSize = tightBoundsWithSelection.Size;
+            cornersToSelectionOffset = new RectD(masterCorners.TopLeft - tightBoundsWithSelection.TopLeft, 
+                tightBoundsSize - masterCorners.RectSize);
         }
-        else
+
+        StructureNode firstLayer = target.FindMemberOrThrow(memberData[0].MemberId);
+        RectD tightBounds = firstLayer.GetTightBounds(frame).Value;
+
+        if (memberData.Count == 1 && firstLayer is VectorLayerNode vectorLayer)
         {
-            StructureNode firstLayer = target.FindMemberOrThrow(memberData[0].MemberId);
-            originalTightBounds = (RectD)firstLayer.GetTightBounds(frame).Value;
-            
-            if(memberData.Count == 1 && firstLayer is VectorLayerNode vectorLayer)
-            {
-                originalTightBounds = vectorLayer.ShapeData.GeometryAABB;
-                // TODO: still some issues in multiple selection
-            }
-            
-            for (var i = 1; i < memberData.Count; i++)
-            {
-                StructureNode layer = target.FindMemberOrThrow(memberData[i].MemberId);
-                originalTightBounds = originalTightBounds.Union((RectD)layer.GetTightBounds(frame).Value);
-            }
+            tightBounds = vectorLayer.ShapeData.GeometryAABB;
+        }
 
-            originalSize = originalTightBounds.Size;
+        for (var i = 1; i < memberData.Count; i++)
+        {
+            StructureNode layer = target.FindMemberOrThrow(memberData[i].MemberId);
+            tightBounds = tightBounds.Union((RectD)layer.GetTightBounds(frame).Value);
         }
 
+        tightBoundsSize = tightBounds.Size;
+
         foreach (var member in memberData)
         {
             StructureNode layer = target.FindMemberOrThrow(member.MemberId);
 
             if (layer is IReadOnlyImageNode)
             {
-                SetImageMember(target, member, originalTightBounds, layer);
+                var targetBounds = tightBoundsWithSelection != default ? tightBoundsWithSelection : tightBounds;
+                SetImageMember(target, member, targetBounds, layer);
             }
             else if (layer is ITransformableObject transformable)
             {
@@ -109,9 +113,10 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
     private void SetTransformableMember(StructureNode layer, MemberTransformationData member,
         ITransformableObject transformable)
     {
-        member.OriginalBounds = (RectD)layer.GetTightBounds(frame).Value;
-        VecD posRelativeToMaster = member.MemberCorners.TopLeft - masterCorners.TopLeft;
-        member.OriginalPos = (VecI)posRelativeToMaster; 
+        member.OriginalBounds = layer.GetTightBounds(frame).Value;
+        VecD posRelativeToMaster = member.OriginalBounds.Value.TopLeft - masterCorners.TopLeft;
+
+        member.OriginalPos = (VecI)posRelativeToMaster;
         member.AddTransformableObject(transformable, transformable.TransformationMatrix);
     }
 
@@ -125,9 +130,9 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
 
         if (pathToExtract == null)
         {
-            RectI tightBounds = layer.GetTightBounds(frame).GetValueOrDefault();
+            RectD tightBounds = layer.GetTightBounds(frame).GetValueOrDefault();
             pathToExtract = new VectorPath();
-            pathToExtract.AddRect(tightBounds);
+            pathToExtract.AddRect((RectI)tightBounds);
         }
 
         member.OriginalPath = pathToExtract;
@@ -145,18 +150,24 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
         this.keepOriginal = keepOriginal;
         this.masterCorners = masterCorners;
 
-        globalMatrix = OperationHelper.CreateMatrixFromPoints(masterCorners, originalSize);
+        var globalMatrixWithSelection = OperationHelper.CreateMatrixFromPoints(masterCorners, originalCornersSize);
+        var tightBoundsGlobalMatrix = OperationHelper.CreateMatrixFromPoints(masterCorners, tightBoundsSize);
 
         foreach (var member in memberData)
         {
-            Matrix3X3 localMatrix = globalMatrix; 
-            
+            Matrix3X3 localMatrix = tightBoundsGlobalMatrix;
+
             if (member.IsImage)
             {
-                localMatrix = Matrix3X3.CreateTranslation(
-                    member.OriginalPos.Value.X - (float)member.OriginalBounds.Value.Left,
-                    member.OriginalPos.Value.Y - (float)member.OriginalBounds.Value.Top);
-                localMatrix = localMatrix.PostConcat(globalMatrix);
+                localMatrix = 
+                    Matrix3X3.CreateTranslation(
+                        (float)-cornersToSelectionOffset.TopLeft.X, (float)-cornersToSelectionOffset.TopLeft.Y)
+                        .PostConcat(
+                    Matrix3X3.CreateTranslation(
+                    (float)member.OriginalPos.Value.X - (float)member.OriginalBounds.Value.Left,
+                    (float)member.OriginalPos.Value.Y - (float)member.OriginalBounds.Value.Top));
+                
+                localMatrix = localMatrix.PostConcat(selectionAwareSize.Length > 0 ? globalMatrixWithSelection : tightBoundsGlobalMatrix);
             }
             else if (member.OriginalMatrix is not null)
             {
@@ -164,9 +175,9 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
                 {
                     localMatrix = member.OriginalMatrix.Value;
                     localMatrix = localMatrix.PostConcat(Matrix3X3.CreateTranslation(
-                        member.OriginalPos.Value.X - (float)member.OriginalBounds.Value.Left,
-                        member.OriginalPos.Value.Y - (float)member.OriginalBounds.Value.Top))
-                        .PostConcat(globalMatrix);
+                            (float)member.OriginalPos.Value.X - (float)member.OriginalBounds.Value.Left,
+                            (float)member.OriginalPos.Value.Y - (float)member.OriginalBounds.Value.Top))
+                        .PostConcat(tightBoundsGlobalMatrix);
                 }
             }
 
@@ -224,7 +235,6 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
             {
                 member.TransformableObject.TransformationMatrix = member.LocalMatrix;
 
-                // TODO: this is probably wrong
                 AffectedArea area = GetTranslationAffectedArea();
                 infos.Add(new TransformObject_ChangeInfo(member.MemberId, area));
             }
@@ -233,7 +243,7 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
         if (isTransformingSelection)
         {
             infos.Add(SelectionChangeHelper.DoSelectionTransform(target, originalPath!, originalSelectionBounds,
-                masterCorners));
+                masterCorners, cornersToSelectionOffset, originalCornersSize));
         }
 
         hasEnqueudImages = false;
@@ -260,7 +270,6 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
             {
                 member.TransformableObject.TransformationMatrix = member.LocalMatrix;
 
-                // TODO: this is probably wrong
                 AffectedArea translationAffectedArea = GetTranslationAffectedArea();
                 infos.Add(new TransformObject_ChangeInfo(member.MemberId, translationAffectedArea));
             }
@@ -269,7 +278,7 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
         if (isTransformingSelection)
         {
             infos.Add(SelectionChangeHelper.DoSelectionTransform(target, originalPath!, originalSelectionBounds,
-                masterCorners));
+                masterCorners, cornersToSelectionOffset, originalCornersSize));
         }
 
         return infos;
@@ -375,7 +384,7 @@ class MemberTransformationData : IDisposable
     public VectorPath? OriginalPath { get; set; }
     public Surface? Image { get; set; }
     public RectD? OriginalBounds { get; set; }
-    public VecI? OriginalPos { get; set; }
+    public VecD? OriginalPos { get; set; }
     public bool IsImage => Image != null;
     public bool IsTransformable => TransformableObject != null;
     public RectI? RoundedOriginalBounds => (RectI)OriginalBounds?.RoundOutwards();

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

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

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changes/Root/ClipCanvas_Change.cs

@@ -24,8 +24,8 @@ internal class ClipCanvas_Change : ResizeBasedChangeBase
                 var layerBounds = layer.GetTightBounds(frameToClip);
                 if (layerBounds.HasValue)
                 {
-                    bounds ??= layerBounds.Value;
-                    bounds = bounds.Value.Union(layerBounds.Value);
+                    bounds ??= (RectI)layerBounds.Value;
+                    bounds = bounds.Value.Union((RectI)layerBounds.Value);
                 }
             }
         });

+ 26 - 2
src/PixiEditor.ChangeableDocument/Changes/Selection/SelectionChangeHelper.cs

@@ -4,6 +4,7 @@ using PixiEditor.DrawingApi.Core.Surfaces.Vector;
 using PixiEditor.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changes.Selection;
+
 internal class SelectionChangeHelper
 {
     public static Selection_ChangeInfo DoSelectionTransform(
@@ -11,8 +12,31 @@ internal class SelectionChangeHelper
     {
         VectorPath newPath = new(originalPath);
 
-        var matrix = Matrix3X3.CreateTranslation((float)-originalPathTightBounds.X, (float)-originalPathTightBounds.Y).PostConcat(
-            OperationHelper.CreateMatrixFromPoints(to, originalPathTightBounds.Size));
+        var matrix = Matrix3X3.CreateTranslation((float)-originalPathTightBounds.X, (float)-originalPathTightBounds.Y)
+            .PostConcat(
+                OperationHelper.CreateMatrixFromPoints(to, originalPathTightBounds.Size));
+        newPath.Transform(matrix);
+        var toDispose = target.Selection.SelectionPath;
+        target.Selection.SelectionPath = newPath;
+        toDispose.Dispose();
+
+        return new Selection_ChangeInfo(new VectorPath(target.Selection.SelectionPath));
+    }
+
+    public static IChangeInfo DoSelectionTransform(Document target, VectorPath originalPath,
+        RectD originalPathTightBounds, ShapeCorners to, RectD cornersToSelectionOffset, VecD originalCornersSize)
+    {
+        VectorPath newPath = new(originalPath);
+
+        var matrix =
+            Matrix3X3.CreateTranslation(-(float)cornersToSelectionOffset.X, -(float)cornersToSelectionOffset.Y);
+
+        matrix = matrix.PostConcat(Matrix3X3.CreateTranslation(
+            (float)(-originalPathTightBounds.X),
+            (float)(-originalPathTightBounds.Y)));
+        
+        matrix = matrix.PostConcat(OperationHelper.CreateMatrixFromPoints(to, originalCornersSize));
+        
         newPath.Transform(matrix);
         var toDispose = target.Selection.SelectionPath;
         target.Selection.SelectionPath = newPath;

+ 1 - 1
src/PixiEditor/Models/Handlers/IStructureMemberHandler.cs

@@ -20,7 +20,7 @@ internal interface IStructureMemberHandler : INodeHandler
     public float OpacityBindable { get; set; }
     public IDocument Document { get; }
     public bool IsVisibleBindable { get; set; }
-    public RectI? TightBounds { get; }
+    public RectD? TightBounds { get; }
     public ShapeCorners TransformationCorners { get; }
     public void SetMaskIsVisible(bool infoIsVisible);
     public void SetClipToMemberBelowEnabled(bool infoClipToMemberBelow);

+ 2 - 2
src/PixiEditor/Models/Rendering/MemberPreviewUpdater.cs

@@ -315,7 +315,7 @@ internal class MemberPreviewUpdater
             return FindImageTightBoundsFast(raster.GetLayerImageAtFrame(frame));
         }
 
-        return layer.GetTightBounds(frame);
+        return (RectI)layer.GetTightBounds(frame);
     }
 
     /// <summary>
@@ -347,7 +347,7 @@ internal class MemberPreviewUpdater
         }
 
         return combinedBounds;*/
-        return folder.GetTightBounds(frame);
+        return (RectI)folder.GetTightBounds(frame);
     }
 
     /// <summary>

+ 1 - 1
src/PixiEditor/ViewModels/Document/Nodes/StructureMemberViewModel.cs

@@ -39,7 +39,7 @@ internal abstract class StructureMemberViewModel<T> : NodeViewModel<T>, IStructu
 
     private bool maskIsVisible;
 
-    public RectI? TightBounds => Internals.Tracker.Document.FindMember(Id)
+    public RectD? TightBounds => Internals.Tracker.Document.FindMember(Id)
         ?.GetTightBounds(Document.AnimationDataViewModel.ActiveFrameBindable);
     
     public ShapeCorners TransformationCorners => Internals.Tracker.Document.FindMember(Id)

+ 1 - 1
src/PixiEditor/ViewModels/Tools/Tools/MoveToolViewModel.cs

@@ -95,7 +95,7 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
             {
                 var foundLayer =
                     ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument.StructureHelper.Find(layer);
-                RectI? layerBounds = foundLayer?.TightBounds;
+                RectI? layerBounds = (RectI?)foundLayer?.TightBounds;
                 if (layerBounds != null)
                 {
                     if (bounds == null)