Browse Source

Fixed transform overlay not resetting corners and paste image

flabbet 11 months ago
parent
commit
e55844d78f

+ 12 - 1
src/PixiEditor/Models/Clipboard/DataImage.cs

@@ -5,7 +5,18 @@ using PixiEditor.Numerics;
 
 
 namespace PixiEditor.Models.Clipboard;
 namespace PixiEditor.Models.Clipboard;
 
 
-public record struct DataImage(string? name, Surface image, VecI position)
+public record struct DataImage
 {
 {
+    public string? Name { get; set; }
+    public Surface Image { get; set; }
+    public VecI Position { get; set; }
+    
     public DataImage(Surface image, VecI position) : this(null, image, position) { }
     public DataImage(Surface image, VecI position) : this(null, image, position) { }
+
+    public DataImage(string? name, Surface image, VecI position)
+    {
+        Name = name;
+        Image = image;
+        Position = position;
+    }
 }
 }

+ 17 - 5
src/PixiEditor/Models/Controllers/ClipboardController.cs

@@ -102,7 +102,7 @@ internal static class ClipboardController
         if (images.Count == 1)
         if (images.Count == 1)
         {
         {
             var dataImage = images[0];
             var dataImage = images[0];
-            var position = dataImage.position;
+            var position = dataImage.Position;
 
 
             if (document.SizeBindable.X < position.X || document.SizeBindable.Y < position.Y)
             if (document.SizeBindable.X < position.X || document.SizeBindable.Y < position.Y)
             {
             {
@@ -119,11 +119,11 @@ internal static class ClipboardController
                 }
                 }
 
 
                 document.Operations.SetSelectedMember(guid.Value);
                 document.Operations.SetSelectedMember(guid.Value);
-                document.Operations.PasteImageWithTransform(dataImage.image, position, guid.Value, false);
+                document.Operations.PasteImageWithTransform(dataImage.Image, position, guid.Value, false);
             }
             }
             else
             else
             {
             {
-                document.Operations.PasteImageWithTransform(dataImage.image, position);
+                document.Operations.PasteImageWithTransform(dataImage.Image, position);
             }
             }
 
 
             return true;
             return true;
@@ -185,15 +185,27 @@ internal static class ClipboardController
 
 
         if (data == null)
         if (data == null)
             return surfaces;
             return surfaces;
+        
+        VecI pos = VecI.NegativeOne;
 
 
         foreach (var dataObject in data)
         foreach (var dataObject in data)
         {
         {
             if (TryExtractSingleImage(dataObject, out var singleImage))
             if (TryExtractSingleImage(dataObject, out var singleImage))
             {
             {
-                surfaces.Add(new DataImage(singleImage, dataObject.GetVecI(PositionFormat)));
+                surfaces.Add(new DataImage(singleImage, dataObject.Contains(PositionFormat) ? dataObject.GetVecI(PositionFormat) : pos));
                 continue;
                 continue;
             }
             }
 
 
+            if (dataObject.Contains(PositionFormat))
+            {
+                pos = dataObject.GetVecI(PositionFormat);
+                for (var i = 0; i < surfaces.Count; i++)
+                {
+                    var surface = surfaces[i];
+                    surfaces[i] = surface with { Position = pos };
+                }
+            }
+
             var paths = dataObject.GetFileDropList().Select(x => x.Path.LocalPath).ToList();
             var paths = dataObject.GetFileDropList().Select(x => x.Path.LocalPath).ToList();
             if (paths != null && dataObject.TryGetRawTextPath(out string? textPath))
             if (paths != null && dataObject.TryGetRawTextPath(out string? textPath))
             {
             {
@@ -360,7 +372,7 @@ internal static class ClipboardController
                     return false;
                     return false;
                 }
                 }
 
 
-                result = imgs[0].image;
+                result = imgs[0].Image;
                 return true;
                 return true;
             }
             }
             else
             else

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

@@ -126,7 +126,7 @@ internal class DocumentOperationsModule : IDocumentOperations
         RectI maxSize = new RectI(VecI.Zero, Document.SizeBindable);
         RectI maxSize = new RectI(VecI.Zero, Document.SizeBindable);
         foreach (var imageWithName in images)
         foreach (var imageWithName in images)
         {
         {
-            maxSize = maxSize.Union(new RectI(imageWithName.position, imageWithName.image.Size));
+            maxSize = maxSize.Union(new RectI(imageWithName.Position, imageWithName.Image.Size));
         }
         }
 
 
         if (maxSize.Size != Document.SizeBindable)
         if (maxSize.Size != Document.SizeBindable)
@@ -134,8 +134,8 @@ internal class DocumentOperationsModule : IDocumentOperations
 
 
         foreach (var imageWithName in images)
         foreach (var imageWithName in images)
         {
         {
-            var layerGuid = Internals.StructureHelper.CreateNewStructureMember(StructureMemberType.Layer, Path.GetFileName(imageWithName.name));
-            DrawImage(imageWithName.image, new ShapeCorners(new RectD(imageWithName.position, imageWithName.image.Size)),
+            var layerGuid = Internals.StructureHelper.CreateNewStructureMember(StructureMemberType.Layer, Path.GetFileName(imageWithName.Name));
+            DrawImage(imageWithName.Image, new ShapeCorners(new RectD(imageWithName.Position, imageWithName.Image.Size)),
                 layerGuid, true, false, frame, false);
                 layerGuid, true, false, frame, false);
         }
         }
         Internals.ActionAccumulator.AddFinishedActions();
         Internals.ActionAccumulator.AddFinishedActions();

+ 11 - 13
src/PixiEditor/ViewModels/Document/TransformOverlays/DocumentTransformViewModel.cs

@@ -6,6 +6,7 @@ using CommunityToolkit.Mvvm.Input;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Extensions.Common.Localization;
 using PixiEditor.Extensions.Common.Localization;
 using PixiEditor.Extensions.Helpers;
 using PixiEditor.Extensions.Helpers;
+using PixiEditor.Helpers.UI;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Handlers;
 using PixiEditor.Numerics;
 using PixiEditor.Numerics;
@@ -91,18 +92,6 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
         set => SetProperty(ref coverWholeScreen, value);
         set => SetProperty(ref coverWholeScreen, value);
     }
     }
 
 
-    private ShapeCorners requestedCorners;
-    public ShapeCorners RequestedCorners
-    {
-        get => requestedCorners;
-        set
-        {
-            // The event must be raised even if the value hasn't changed, so I'm not using SetProperty
-            requestedCorners = value;
-            OnPropertyChanged(nameof(RequestedCorners));
-        }
-    }
-
     private ShapeCorners corners;
     private ShapeCorners corners;
     public ShapeCorners Corners
     public ShapeCorners Corners
     {
     {
@@ -113,6 +102,13 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
             TransformMoved?.Invoke(this, value);
             TransformMoved?.Invoke(this, value);
         }
         }
     }
     }
+    
+    private ExecutionTrigger<ShapeCorners> requestedCornersExecutor;
+    public ExecutionTrigger<ShapeCorners> RequestCornersExecutor
+    {
+        get => requestedCornersExecutor;
+        set => SetProperty(ref requestedCornersExecutor, value);
+    }
 
 
     private ICommand? actionCompletedCommand = null;
     private ICommand? actionCompletedCommand = null;
     public ICommand? ActionCompletedCommand
     public ICommand? ActionCompletedCommand
@@ -139,6 +135,8 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
 
 
             undoStack.AddState((Corners, InternalState), TransformOverlayStateType.Move);
             undoStack.AddState((Corners, InternalState), TransformOverlayStateType.Move);
         });
         });
+
+        RequestCornersExecutor = new ExecutionTrigger<ShapeCorners>();
     }
     }
 
 
     public bool Undo()
     public bool Undo()
@@ -194,12 +192,12 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
         CornerFreedom = TransformCornerFreedom.Scale;
         CornerFreedom = TransformCornerFreedom.Scale;
         SideFreedom = TransformSideFreedom.Stretch;
         SideFreedom = TransformSideFreedom.Stretch;
         LockRotation = mode == DocumentTransformMode.Scale_NoRotate_NoShear_NoPerspective;
         LockRotation = mode == DocumentTransformMode.Scale_NoRotate_NoShear_NoPerspective;
-        RequestedCorners = initPos;
         CoverWholeScreen = coverWholeScreen;
         CoverWholeScreen = coverWholeScreen;
         TransformActive = true;
         TransformActive = true;
         ShowTransformControls = showApplyButton;
         ShowTransformControls = showApplyButton;
 
 
         undoStack.AddState((Corners, InternalState), TransformOverlayStateType.Initial);
         undoStack.AddState((Corners, InternalState), TransformOverlayStateType.Initial);
+        RequestCornersExecutor?.Execute(this, initPos);
     }
     }
 
 
     public void KeyModifiersInlet(bool isShiftDown, bool isCtrlDown, bool isAltDown)
     public void KeyModifiersInlet(bool isShiftDown, bool isCtrlDown, bool isAltDown)

+ 3 - 3
src/PixiEditor/ViewModels/SubViewModels/ClipboardViewModel.cs

@@ -61,15 +61,15 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
 
 
         DataImage imageData = (data == null ? await ClipboardController.GetImagesFromClipboard() : ClipboardController.GetImage(new [] { data })).First();
         DataImage imageData = (data == null ? await ClipboardController.GetImagesFromClipboard() : ClipboardController.GetImage(new [] { data })).First();
-        using var surface = imageData.image;
+        using var surface = imageData.Image;
 
 
-        var bitmap = imageData.image.ToWriteableBitmap();
+        var bitmap = imageData.Image.ToWriteableBitmap();
 
 
         byte[] pixels = bitmap.ExtractPixels();
         byte[] pixels = bitmap.ExtractPixels();
 
 
         doc.Operations.ImportReferenceLayer(
         doc.Operations.ImportReferenceLayer(
             pixels.ToImmutableArray(),
             pixels.ToImmutableArray(),
-            imageData.image.Size);
+            imageData.Image.Size);
 
 
         if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
         if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
         {
         {

+ 3 - 3
src/PixiEditor/ViewModels/SubViewModels/FileViewModel.cs

@@ -169,13 +169,13 @@ internal class FileViewModel : SubViewModel<ViewModelMain>
 
 
         foreach (var dataImage in images)
         foreach (var dataImage in images)
         {
         {
-            if (File.Exists(dataImage.name))
+            if (File.Exists(dataImage.Name))
             {
             {
-                OpenRegularImage(dataImage.image, null);
+                OpenRegularImage(dataImage.Image, null);
                 continue;
                 continue;
             }
             }
 
 
-            OpenRegularImage(dataImage.image, null);
+            OpenRegularImage(dataImage.Image, null);
         }
         }
     }
     }
 
 

+ 2 - 3
src/PixiEditor/Views/Main/ViewportControls/ViewportOverlays.cs

@@ -236,8 +236,7 @@ internal class ViewportOverlays
         Binding requestedCornersBinding = new()
         Binding requestedCornersBinding = new()
         {
         {
             Source = Viewport,
             Source = Viewport,
-            Path = "Document.TransformViewModel.RequestedCorners",
-            Mode = BindingMode.TwoWay
+            Path = "Document.TransformViewModel.RequestCornersExecutor",
         };
         };
 
 
         Binding cornerFreedomBinding = new()
         Binding cornerFreedomBinding = new()
@@ -292,7 +291,7 @@ internal class ViewportOverlays
         transformOverlay.Bind(Visual.IsVisibleProperty, isVisibleBinding);
         transformOverlay.Bind(Visual.IsVisibleProperty, isVisibleBinding);
         transformOverlay.Bind(TransformOverlay.ActionCompletedProperty, actionCompletedBinding);
         transformOverlay.Bind(TransformOverlay.ActionCompletedProperty, actionCompletedBinding);
         transformOverlay.Bind(TransformOverlay.CornersProperty, cornersBinding);
         transformOverlay.Bind(TransformOverlay.CornersProperty, cornersBinding);
-        transformOverlay.Bind(TransformOverlay.RequestedCornersProperty, requestedCornersBinding);
+        transformOverlay.Bind(TransformOverlay.RequestCornersExecutorProperty, requestedCornersBinding);
         transformOverlay.Bind(TransformOverlay.CornerFreedomProperty, cornerFreedomBinding);
         transformOverlay.Bind(TransformOverlay.CornerFreedomProperty, cornerFreedomBinding);
         transformOverlay.Bind(TransformOverlay.SideFreedomProperty, sideFreedomBinding);
         transformOverlay.Bind(TransformOverlay.SideFreedomProperty, sideFreedomBinding);
         transformOverlay.Bind(TransformOverlay.LockRotationProperty, lockRotationBinding);
         transformOverlay.Bind(TransformOverlay.LockRotationProperty, lockRotationBinding);

+ 29 - 26
src/PixiEditor/Views/Overlays/TransformOverlay/TransformOverlay.cs

@@ -10,6 +10,7 @@ using PixiEditor.Helpers;
 using PixiEditor.Helpers.Extensions;
 using PixiEditor.Helpers.Extensions;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Extensions.UI.Overlays;
 using PixiEditor.Extensions.UI.Overlays;
+using PixiEditor.Helpers.UI;
 using PixiEditor.Numerics;
 using PixiEditor.Numerics;
 using PixiEditor.Views.Overlays.Handles;
 using PixiEditor.Views.Overlays.Handles;
 using Point = Avalonia.Point;
 using Point = Avalonia.Point;
@@ -18,15 +19,6 @@ namespace PixiEditor.Views.Overlays.TransformOverlay;
 #nullable enable
 #nullable enable
 internal class TransformOverlay : Overlay
 internal class TransformOverlay : Overlay
 {
 {
-    public static readonly StyledProperty<ShapeCorners> RequestedCornersProperty =
-        AvaloniaProperty.Register<TransformOverlay, ShapeCorners>(nameof(RequestedCorners), defaultValue: default(ShapeCorners));
-
-    public ShapeCorners RequestedCorners
-    {
-        get => GetValue(RequestedCornersProperty);
-        set => SetValue(RequestedCornersProperty, value);
-    }
-
     public static readonly StyledProperty<ShapeCorners> CornersProperty =
     public static readonly StyledProperty<ShapeCorners> CornersProperty =
         AvaloniaProperty.Register<TransformOverlay, ShapeCorners>(nameof(Corners), defaultValue: default(ShapeCorners));
         AvaloniaProperty.Register<TransformOverlay, ShapeCorners>(nameof(Corners), defaultValue: default(ShapeCorners));
 
 
@@ -99,6 +91,15 @@ internal class TransformOverlay : Overlay
         set => SetValue(CoverWholeScreenProperty, value);
         set => SetValue(CoverWholeScreenProperty, value);
     }
     }
 
 
+    public static readonly StyledProperty<ExecutionTrigger<ShapeCorners>> RequestCornersExecutorProperty = AvaloniaProperty.Register<TransformOverlay, ExecutionTrigger<ShapeCorners>>(
+        nameof(RequestCornersExecutor));
+
+    public ExecutionTrigger<ShapeCorners> RequestCornersExecutor
+    {
+        get => GetValue(RequestCornersExecutorProperty);
+        set => SetValue(RequestCornersExecutorProperty, value);
+    }
+
     public static readonly StyledProperty<ICommand?> ActionCompletedProperty =
     public static readonly StyledProperty<ICommand?> ActionCompletedProperty =
         AvaloniaProperty.Register<TransformOverlay, ICommand?>(nameof(ActionCompleted));
         AvaloniaProperty.Register<TransformOverlay, ICommand?>(nameof(ActionCompleted));
 
 
@@ -110,14 +111,13 @@ internal class TransformOverlay : Overlay
 
 
     static TransformOverlay()
     static TransformOverlay()
     {
     {
-        AffectsRender<TransformOverlay>(RequestedCornersProperty, CornersProperty, ZoomScaleProperty, SideFreedomProperty, CornerFreedomProperty, LockRotationProperty, SnapToAnglesProperty, InternalStateProperty, ZoomboxAngleProperty, CoverWholeScreenProperty);
+        AffectsRender<TransformOverlay>(CornersProperty, ZoomScaleProperty, SideFreedomProperty, CornerFreedomProperty, LockRotationProperty, SnapToAnglesProperty, InternalStateProperty, ZoomboxAngleProperty, CoverWholeScreenProperty);
 
 
-        RequestedCornersProperty.Changed.Subscribe(OnRequestedCorners);
+        RequestCornersExecutorProperty.Changed.Subscribe(OnCornersExecutorChanged);
     }
     }
 
 
     private const int anchorSizeMultiplierForRotation = 15;
     private const int anchorSizeMultiplierForRotation = 15;
 
 
-    private bool isResettingRequestedCorners = false;
     private bool isMoving = false;
     private bool isMoving = false;
     private VecD mousePosOnStartMove = new();
     private VecD mousePosOnStartMove = new();
     private VecD originOnStartMove = new();
     private VecD originOnStartMove = new();
@@ -616,23 +616,26 @@ internal class TransformOverlay : Overlay
         return null;
         return null;
     }
     }
 
 
-    private static void OnRequestedCorners(AvaloniaPropertyChangedEventArgs<ShapeCorners> args)
+    private void OnRequestedCorners(object sender, ShapeCorners corners)
     {
     {
-        TransformOverlay overlay = (TransformOverlay)args.Sender;
-        if (overlay.isResettingRequestedCorners)
-            return;
-        overlay.isMoving = false;
-        overlay.isRotating = false;
-        overlay.Corners = args.NewValue.Value;
-        overlay.InternalState = new()
+        isMoving = false;
+        isRotating = false;
+        Corners = corners; 
+        InternalState = new()
         {
         {
-            ProportionalAngle1 = (overlay.Corners.BottomRight - overlay.Corners.TopLeft).Angle,
-            ProportionalAngle2 = (overlay.Corners.TopRight - overlay.Corners.BottomLeft).Angle,
+            ProportionalAngle1 = (Corners.BottomRight - Corners.TopLeft).Angle,
+            ProportionalAngle2 = (Corners.TopRight - Corners.BottomLeft).Angle,
             OriginWasManuallyDragged = false,
             OriginWasManuallyDragged = false,
-            Origin = TransformHelper.OriginFromCorners(overlay.Corners),
+            Origin = TransformHelper.OriginFromCorners(Corners),
         };
         };
-        overlay.isResettingRequestedCorners = true;
-        //overlay.RequestedCorners = new ShapeCorners();
-        overlay.isResettingRequestedCorners = false;
+    }
+    
+    private static void OnCornersExecutorChanged(AvaloniaPropertyChangedEventArgs<ExecutionTrigger<ShapeCorners>> args)
+    {
+        TransformOverlay overlay = (TransformOverlay)args.Sender;
+        if (args.OldValue != null)
+            args.OldValue.Value.Triggered -= overlay.OnRequestedCorners;
+        if (args.NewValue != null)
+            args.NewValue.Value.Triggered += overlay.OnRequestedCorners;
     }
     }
 }
 }