Browse Source

Copied area now stays in the same place as where it was copied from #521

CPKreuz 2 years ago
parent
commit
8e137fee8c

+ 19 - 0
src/PixiEditor.DrawingApi.Core/Numerics/VecI.cs

@@ -68,6 +68,25 @@ public struct VecI : IEquatable<VecI>
     {
         return new(X, 2 * lineY - Y);
     }
+
+    public byte[] ToByteArray()
+    {
+        var data = new byte[sizeof(int) * 2];
+
+        BitConverter.TryWriteBytes(data, X);
+        BitConverter.TryWriteBytes(data.AsSpan(4), Y);
+
+        return data;
+    }
+
+    public static VecI FromBytes(ReadOnlySpan<byte> value)
+    {
+        var x = BitConverter.ToInt32(value);
+        var y = BitConverter.ToInt32(value[4..]);
+
+        return new VecI(x, y);
+    }
+    
     public static VecI operator +(VecI a, VecI b)
     {
         return new VecI(a.X + b.X, a.Y + b.Y);

+ 7 - 2
src/PixiEditor/Helpers/ClipboardHelper.cs

@@ -1,8 +1,9 @@
 using System.Windows;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.Helpers;
 
-class ClipboardHelper
+internal static class ClipboardHelper
 {
     public static bool TrySetDataObject(DataObject obj, bool copy)
     {
@@ -41,4 +42,8 @@ class ClipboardHelper
             return false;
         }
     }
-}
+    
+    public static VecI GetVecI(this DataObject data, string format) => VecI.FromBytes((byte[])data.GetData(format));
+
+    public static void SetVecI(this DataObject data, string format, VecI value) => data.SetData(format, value.ToByteArray());
+}

+ 62 - 44
src/PixiEditor/Models/Controllers/ClipboardController.cs

@@ -21,6 +21,8 @@ namespace PixiEditor.Models.Controllers;
 #nullable enable
 internal static class ClipboardController
 {
+    private const string PositionFormat = "PixiEditor.Position";
+    
     public static readonly string TempCopyFilePath = Path.Join(
         Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
         "PixiEditor",
@@ -42,7 +44,7 @@ internal static class ClipboardController
             NoticeDialog.Show("SELECTED_AREA_EMPTY", "NOTHING_TO_COPY");
             return;
         }
-        var (actuallySurface, _) = surface.AsT2;
+        var (actuallySurface, area) = surface.AsT2;
         DataObject data = new DataObject();
 
         using (ImgData pngData = actuallySurface.DrawingSurface.Snapshot().Encode())
@@ -64,6 +66,11 @@ internal static class ClipboardController
         data.SetData(DataFormats.Bitmap, finalBitmap, true); // Bitmap, no transparency
         data.SetImage(finalBitmap); // DIB format, no transparency
 
+        if (area.Size != document.SizeBindable && area.Pos != VecI.Zero)
+        {
+            data.SetVecI(PositionFormat, area.Pos);
+        }
+
         ClipboardHelper.TrySetDataObject(data, true);
     }
 
@@ -72,12 +79,14 @@ internal static class ClipboardController
     /// </summary>
     public static bool TryPaste(DocumentViewModel document, DataObject data, bool pasteAsNew = false)
     {
-        List<(string? name, Surface image)> images = GetImage(data);
+        List<DataImage> images = GetImage(data);
         if (images.Count == 0)
             return false;
 
         if (images.Count == 1)
         {
+            var dataImage = images[0];
+            
             if (pasteAsNew)
             {
                 var guid = document.Operations.CreateStructureMember(StructureMemberType.Layer, "New Layer", false);
@@ -88,11 +97,11 @@ internal static class ClipboardController
                 }
                 
                 document.Operations.SetSelectedMember(guid.Value);
-                document.Operations.PasteImageWithTransform(images[0].image, VecI.Zero, guid.Value, false);
+                document.Operations.PasteImageWithTransform(dataImage.image, dataImage.position, guid.Value, false);
             }
             else
             {
-                document.Operations.PasteImageWithTransform(images[0].image, VecI.Zero);
+                document.Operations.PasteImageWithTransform(dataImage.image, dataImage.position);
             }
             
             return true;
@@ -108,72 +117,76 @@ internal static class ClipboardController
     public static bool TryPasteFromClipboard(DocumentViewModel document, bool pasteAsNew = false) =>
         TryPaste(document, ClipboardHelper.TryGetDataObject(), pasteAsNew);
 
-    public static List<(string? name, Surface image)> GetImagesFromClipboard() => GetImage(ClipboardHelper.TryGetDataObject());
+    public static List<DataImage> GetImagesFromClipboard() => GetImage(ClipboardHelper.TryGetDataObject());
 
     /// <summary>
     /// Gets images from clipboard, supported PNG, Dib and Bitmap.
     /// </summary>
-    public static List<(string? name, Surface image)> GetImage(DataObject? data)
+    public static List<DataImage> GetImage(DataObject? data)
     {
-        List<(string? name, Surface image)> surfaces = new();
+        List<DataImage> surfaces = new();
 
         if (data == null)
             return surfaces;
 
-        if (TryExtractSingleImage(data, out Surface? singleImage))
+        if (TryExtractSingleImage(data, out var singleImage))
+        {
+            surfaces.Add(new DataImage(singleImage, data.GetVecI(PositionFormat)));
+            return surfaces;
+        }
+
+        if (!data.GetDataPresent(DataFormats.FileDrop))
         {
-            surfaces.Add((null, singleImage));
             return surfaces;
         }
-        else if (data.GetDataPresent(DataFormats.FileDrop))
+
+        foreach (string? path in data.GetFileDropList())
         {
-            foreach (string? path in data.GetFileDropList())
+            if (path is null || !Importer.IsSupportedFile(path))
+                continue;
+            try
             {
-                if (path is null || !Importer.IsSupportedFile(path))
-                    continue;
-                try
-                {
-                    Surface imported;
+                Surface imported;
                     
-                    if (Path.GetExtension(path) == ".pixi")
-                    {
-                        using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
+                if (Path.GetExtension(path) == ".pixi")
+                {
+                    using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
                         
-                        try
+                    try
+                    {
+                        imported = Surface.Load(PixiParser.Deserialize(path).PreviewImage);
+                    }
+                    catch (InvalidFileException e)
+                    {
+                        // Check if it could be a old file
+                        if (!e.Message.StartsWith("Header"))
                         {
-                            imported = Surface.Load(PixiParser.Deserialize(path).PreviewImage);
+                            throw;
                         }
-                        catch (InvalidFileException e)
-                        {
-                            // Check if it could be a old file
-                            if (!e.Message.StartsWith("Header"))
-                            {
-                                throw;
-                            }
                             
-                            stream.Position = 0;
-                            using var bitmap = DepractedPixiParser.Deserialize(stream).RenderOldDocument();
-                            var size = new VecI(bitmap.Width, bitmap.Height);
-                            imported = new Surface(size);
-                            imported.DrawBytes(size, bitmap.Bytes, ColorType.RgbaF32, AlphaType.Premul);
+                        stream.Position = 0;
+                        using var bitmap = DepractedPixiParser.Deserialize(stream).RenderOldDocument();
+                        var size = new VecI(bitmap.Width, bitmap.Height);
+                        imported = new Surface(size);
+                        imported.DrawBytes(size, bitmap.Bytes, ColorType.RgbaF32, AlphaType.Premul);
                             
-                            System.Diagnostics.Debug.Write(imported.ToString());
-                        }
+                        System.Diagnostics.Debug.Write(imported.ToString());
                     }
-                    else
-                    {
-                        imported = Surface.Load(path);
-                    }
-
-                    string filename = Path.GetFullPath(path);
-                    surfaces.Add((filename, imported));
                 }
-                catch
+                else
                 {
-                    continue;
+                    imported = Surface.Load(path);
                 }
+
+                string filename = Path.GetFullPath(path);
+                surfaces.Add(new DataImage(filename, imported, data.GetVecI(PositionFormat)));
+            }
+            catch
+            {
+                continue;
             }
         }
+        
         return surfaces;
     }
 
@@ -259,4 +272,9 @@ internal static class ClipboardController
         result = null;
         return false;
     }
+
+    public record struct DataImage(string? name, Surface image, VecI position)
+    {
+        public DataImage(Surface image, VecI position) : this(null, image, position) { }
+    }
 }

+ 4 - 3
src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs

@@ -7,6 +7,7 @@ using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface.Vector;
+using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 using PixiEditor.Models.DocumentPassthroughActions;
 using PixiEditor.Models.Enums;
@@ -105,7 +106,7 @@ internal class DocumentOperationsModule
     /// Pastes the <paramref name="images"/> as new layers
     /// </summary>
     /// <param name="images">The images to paste</param>
-    public void PasteImagesAsLayers(List<(string? name, Surface image)> images)
+    public void PasteImagesAsLayers(List<ClipboardController.DataImage> images)
     {
         if (Internals.ChangeController.IsChangeActive)
             return;
@@ -113,7 +114,7 @@ internal class DocumentOperationsModule
         RectI maxSize = new RectI(VecI.Zero, Document.SizeBindable);
         foreach (var imageWithName in images)
         {
-            maxSize = maxSize.Union(new RectI(VecI.Zero, imageWithName.image.Size));
+            maxSize = maxSize.Union(new RectI(imageWithName.position, imageWithName.image.Size));
         }
 
         if (maxSize.Size != Document.SizeBindable)
@@ -122,7 +123,7 @@ internal class DocumentOperationsModule
         foreach (var imageWithName in images)
         {
             var layerGuid = Internals.StructureHelper.CreateNewStructureMember(StructureMemberType.Layer, Path.GetFileName(imageWithName.name));
-            DrawImage(imageWithName.image, new ShapeCorners(new RectD(VecD.Zero, imageWithName.image.Size)), layerGuid, true, false, false);
+            DrawImage(imageWithName.image, new ShapeCorners(new RectD(imageWithName.position, imageWithName.image.Size)), layerGuid, true, false, false);
         }
         Internals.ActionAccumulator.AddFinishedActions();
     }

+ 4 - 4
src/PixiEditor/ViewModels/SubViewModels/Main/FileViewModel.cs

@@ -148,15 +148,15 @@ internal class FileViewModel : SubViewModel<ViewModelMain>
     {
         var images = ClipboardController.GetImagesFromClipboard();
 
-        foreach (var (name, image) in images)
+        foreach (var dataImage in images)
         {
-            if (name == null)
+            if (File.Exists(dataImage.name))
             {
-                OpenRegularImage(image, null);
+                OpenRegularImage(dataImage.image, null);
                 continue;
             }
             
-            OpenFromPath(name, false);
+            OpenFromPath(dataImage.name, false);
         }
     }