Kaynağa Gözat

Fixed can shear, added dispose checks, mergning vectors crash

flabbet 8 ay önce
ebeveyn
işleme
7a8c62cff4

+ 2 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/NodeGraph.cs

@@ -81,6 +81,8 @@ public class NodeGraph : IReadOnlyNodeGraph, IDisposable
             
             if (node is Node typedNode)
             {
+                if(typedNode.IsDisposed) continue;
+                
                 typedNode.ExecuteInternal(context);
             }
             else

+ 13 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/Data/LineVectorData.cs

@@ -9,10 +9,10 @@ using Drawie.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.Data;
 
-public class LineVectorData(VecD startPos, VecD pos) : ShapeVectorData, IReadOnlyLineData
+public class LineVectorData : ShapeVectorData, IReadOnlyLineData
 {
-    public VecD Start { get; set; } = startPos;
-    public VecD End { get; set; } = pos;
+    public VecD Start { get; set; }
+    public VecD End { get; set; }
 
     public VecD TransformedStart
     {
@@ -53,6 +53,15 @@ public class LineVectorData(VecD startPos, VecD pos) : ShapeVectorData, IReadOnl
     public override ShapeCorners TransformationCorners => new ShapeCorners(GeometryAABB)
         .WithMatrix(TransformationMatrix);
 
+
+    public LineVectorData(VecD startPos, VecD pos)
+    {
+        Start = startPos;
+        End = pos;
+        
+        Fill = false;
+    }
+
     public override void RasterizeGeometry(Canvas canvas)
     {
         Rasterize(canvas, false);
@@ -104,7 +113,7 @@ public class LineVectorData(VecD startPos, VecD pos) : ShapeVectorData, IReadOnl
     public override VectorPath ToPath()
     {
         // TODO: Apply transformation matrix
-        
+
         VectorPath path = new VectorPath();
         path.MoveTo((VecF)Start);
         path.LineTo((VecF)End);

+ 30 - 13
src/PixiEditor.ChangeableDocument/Changes/Drawing/CombineStructureMembersOnto_Change.cs

@@ -22,7 +22,7 @@ internal class CombineStructureMembersOnto_Change : Change
 
     private Guid targetLayerGuid;
     private Dictionary<int, CommittedChunkStorage> originalChunks = new();
-    
+
     private Dictionary<int, VectorPath> originalPaths = new();
 
 
@@ -160,7 +160,7 @@ internal class CombineStructureMembersOnto_Change : Change
         VectorPath? targetPath = targetData?.ToPath();
 
         var reversed = toCombine.Reverse().ToHashSet();
-        
+
         foreach (var guid in reversed)
         {
             if (target.FindMember(guid) is not VectorLayerNode vectorNode)
@@ -175,10 +175,10 @@ internal class CombineStructureMembersOnto_Change : Change
             {
                 targetData = vectorNode.ShapeData;
                 targetPath = path;
-                
-                if(originalPaths.ContainsKey(frame))
+
+                if (originalPaths.ContainsKey(frame))
                     originalPaths[frame].Dispose();
-                
+
                 originalPaths[frame] = new VectorPath(path);
             }
             else
@@ -188,10 +188,27 @@ internal class CombineStructureMembersOnto_Change : Change
             }
         }
 
-        var pathData = (PathVectorData)targetData.Clone();
-        pathData.Path = targetPath;
+        var clone = targetData.Clone();
+        PathVectorData data;
+        if (clone is not PathVectorData vectorData)
+        {
+            ShapeVectorData shape = clone as ShapeVectorData;
+            data = new PathVectorData(targetPath)
+            {
+                StrokeColor = shape.StrokeColor,
+                FillColor = shape.FillColor,
+                StrokeWidth = shape.StrokeWidth,
+                Fill = shape.Fill,
+                TransformationMatrix = shape.TransformationMatrix,
+            };
+        }
+        else
+        {
+            data = vectorData;
+            data.Path = targetPath;
+        }
 
-        vectorLayer.ShapeData = pathData;
+        vectorLayer.ShapeData = data;
 
         return new AffectedArea(new HashSet<VecI>());
     }
@@ -324,7 +341,7 @@ internal class CombineStructureMembersOnto_Change : Change
         {
             return VectorRevert(vectorLayerNode, frame);
         }
-        
+
         throw new InvalidOperationException("Layer type not supported");
     }
 
@@ -343,7 +360,7 @@ internal class CombineStructureMembersOnto_Change : Change
         toDrawOnImage.CommitChanges();
         return new LayerImageArea_ChangeInfo(targetLayerGuid, affectedArea);
     }
-    
+
     private IChangeInfo VectorRevert(VectorLayerNode targetLayer, int frame)
     {
         if (!originalPaths.TryGetValue(frame, out var path))
@@ -359,14 +376,14 @@ internal class CombineStructureMembersOnto_Change : Change
         {
             originalChunk.Value.Dispose();
         }
-        
+
         originalChunks.Clear();
-        
+
         foreach (var originalPath in originalPaths)
         {
             originalPath.Value.Dispose();
         }
-        
+
         originalPaths.Clear();
     }
 }

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/DrawableShapeToolExecutor.cs

@@ -96,7 +96,7 @@ internal abstract class DrawableShapeToolExecutor<T> : SimpleShapeToolExecutor w
             
             ShapeCorners corners = vectorLayerHandler.TransformationCorners;
             document.TransformHandler.ShowTransform(
-                DocumentTransformMode.Scale_Rotate_Shear_NoPerspective, false, corners, false, UseGlobalUndo ? AddToUndo : null);
+                TransformMode, false, corners, false, UseGlobalUndo ? AddToUndo : null);
             document.TransformHandler.CanAlignToPixels = false;
 
             ActiveMode = ShapeToolMode.Transform;

+ 1 - 1
src/PixiEditor/Models/Rendering/SceneRenderer.cs

@@ -24,7 +24,7 @@ internal class SceneRenderer
 
     public void RenderScene(DrawingSurface target, ChunkResolution resolution)
     {
-        if(Document.Renderer.IsBusy) return;
+        if(Document.Renderer.IsBusy || DocumentViewModel.Busy) return;
         RenderOnionSkin(target, resolution);
         RenderGraph(target, resolution);
     }

+ 14 - 1
src/PixiEditor/ViewModels/Document/TransformOverlays/DocumentTransformViewModel.cs

@@ -61,6 +61,13 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
         get => lockRotation;
         set => SetProperty(ref lockRotation, value);
     }
+    
+    private bool lockShear;
+    public bool LockShear
+    {
+        get => lockShear;
+        set => SetProperty(ref lockShear, value);
+    }
 
     private bool snapToAngles;
 
@@ -263,6 +270,7 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
         CornerFreedom = TransformCornerFreedom.Scale;
         SideFreedom = TransformSideFreedom.Stretch;
         LockRotation = mode == DocumentTransformMode.Scale_NoRotate_NoShear_NoPerspective;
+        LockShear = mode is DocumentTransformMode.Scale_Rotate_NoShear_NoPerspective or DocumentTransformMode.Scale_NoRotate_NoShear_NoPerspective;
         CoverWholeScreen = coverWholeScreen;
         TransformActive = true;
         ShowTransformControls = showApplyButton;
@@ -270,7 +278,7 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
 
         IsSizeBoxEnabled = false;
         ShowHandles = true;
-
+        
         RequestCornersExecutor?.Execute(this, initPos);
 
         if (customAddToUndo is not null)
@@ -309,6 +317,11 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
 
         ScaleFromCenter = isCtrlDown;
 
+        UpdateFreedom(requestedCornerFreedom, requestedSideFreedom);
+    }
+
+    private void UpdateFreedom(TransformCornerFreedom requestedCornerFreedom, TransformSideFreedom requestedSideFreedom)
+    {
         switch (activeTransformMode)
         {
             case DocumentTransformMode.Scale_Rotate_Shear_Perspective:

+ 6 - 0
src/PixiEditor/Views/Main/ViewportControls/ViewportOverlays.cs

@@ -342,6 +342,11 @@ internal class ViewportOverlays
         {
             Source = Viewport, Path = "Document.TransformViewModel.CanAlignToPixels", Mode = BindingMode.OneWay
         };
+        
+        Binding lockShearBinding = new()
+        {
+            Source = Viewport, Path = "Document.TransformViewModel.LockShear", Mode = BindingMode.OneWay
+        };
 
         transformOverlay.Bind(Visual.IsVisibleProperty, isVisibleBinding);
         transformOverlay.Bind(TransformOverlay.ActionCompletedProperty, actionCompletedBinding);
@@ -360,6 +365,7 @@ internal class ViewportOverlays
         transformOverlay.Bind(TransformOverlay.IsSizeBoxEnabledProperty, isSizeBoxEnabledBinding);
         transformOverlay.Bind(TransformOverlay.ScaleFromCenterProperty, scaleFromCenterBinding);
         transformOverlay.Bind(TransformOverlay.CanAlignToPixelsProperty, canAlignToPixelsBinding);
+        transformOverlay.Bind(TransformOverlay.LockShearProperty, lockShearBinding);
     }
     
     private void BindVectorPathOverlay()

+ 16 - 1
src/PixiEditor/Views/Overlays/TransformOverlay/TransformOverlay.cs

@@ -171,6 +171,15 @@ internal class TransformOverlay : Overlay
         set => SetValue(CanAlignToPixelsProperty, value);
     }
 
+    public static readonly StyledProperty<bool> LockShearProperty = AvaloniaProperty.Register<TransformOverlay, bool>(
+        nameof(LockShear));
+
+    public bool LockShear
+    {
+        get => GetValue(LockShearProperty);
+        set => SetValue(LockShearProperty, value);
+    }
+    
     static TransformOverlay()
     {
         AffectsRender<TransformOverlay>(CornersProperty, ZoomScaleProperty, SideFreedomProperty, CornerFreedomProperty,
@@ -687,6 +696,12 @@ internal class TransformOverlay : Overlay
 
     private bool CanShear(VecD mousePos, out Anchor side)
     {
+        if(LockShear)
+        {
+            side = default;
+            return false;
+        }
+        
         double distance = 20 / ZoomScale;
         var sides = new[] { Anchor.Top, Anchor.Bottom, Anchor.Left, Anchor.Right };
 
@@ -700,7 +715,7 @@ internal class TransformOverlay : Overlay
         side = sides.FirstOrDefault(side => VecD.Distance(TransformHelper.GetAnchorPosition(Corners, side), mousePos)
                                             < distance);
 
-        return side != default;
+        return side != default && !Corners.IsPointInside(mousePos);
     }
 
     private void StopMoving()