Kaynağa Gözat

Fixed blending again, snapping improvements and transient press

Krzysztof Krysiński 4 ay önce
ebeveyn
işleme
e03e0c207e

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

@@ -42,7 +42,7 @@ public abstract class RenderNode : Node, IPreviewRenderable, IHighDpiRenderNode
         lastDocumentSize = context.DocumentSize;
     }
 
-    private void Paint(RenderContext context, DrawingSurface surface)
+    protected virtual void Paint(RenderContext context, DrawingSurface surface)
     {
         DrawingSurface target = surface;
         bool useIntermediate = !AllowHighDpiRendering
@@ -51,15 +51,6 @@ public abstract class RenderNode : Node, IPreviewRenderable, IHighDpiRenderNode
         if (useIntermediate)
         {
             Texture intermediate = textureCache.RequestTexture(-6451, context.DocumentSize, context.ProcessingColorSpace);
-
-            int saved = intermediate.DrawingSurface.Canvas.Save();
-            Matrix3X3 fitMatrix = Matrix3X3.CreateScale(
-                (float)context.DocumentSize.X / surface.DeviceClipBounds.Size.X,
-                (float)context.DocumentSize.Y / surface.DeviceClipBounds.Size.Y);
-            intermediate.DrawingSurface.Canvas.SetMatrix(fitMatrix);
-            intermediate.DrawingSurface.Canvas.DrawSurface(surface, 0, 0);
-            intermediate.DrawingSurface.Canvas.RestoreToCount(saved);
-
             target = intermediate.DrawingSurface;
         }
 

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

@@ -124,6 +124,11 @@ public abstract class StructureNode : RenderNode, IReadOnlyStructureNode, IRende
         }
     }
 
+    protected override void Paint(RenderContext context, DrawingSurface surface)
+    {
+        OnPaint(context, surface);
+    }
+
     protected override void OnPaint(RenderContext context, DrawingSurface renderTarget)
     {
         if (Output.Connections.Count > 0)

+ 5 - 6
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/DrawableShapeToolExecutor.cs

@@ -128,7 +128,7 @@ internal abstract class DrawableShapeToolExecutor<T> : SimpleShapeToolExecutor w
     protected abstract void DrawShape(VecD currentPos, double rotationRad, bool firstDraw);
     protected abstract IAction SettingsChangedAction(string name, object value);
     protected abstract IAction TransformMovedAction(ShapeData data, ShapeCorners corners);
-    protected virtual bool InitShapeData(IReadOnlyShapeVectorData data) { return true; }
+    protected virtual bool InitShapeData(IReadOnlyShapeVectorData data) { return false; }
     protected abstract bool CanEditShape(IStructureMemberHandler layer);
     protected abstract IAction EndDrawAction();
     protected virtual DocumentTransformMode TransformMode => DocumentTransformMode.Scale_Rotate_NoShear_NoPerspective;
@@ -234,7 +234,6 @@ internal abstract class DrawableShapeToolExecutor<T> : SimpleShapeToolExecutor w
                 EndDrawAction(),
                 SettingsChangedAction("FillAndStroke", color),
                 EndDrawAction());
-            // TODO add to undo
         }
     }
 
@@ -315,7 +314,7 @@ internal abstract class DrawableShapeToolExecutor<T> : SimpleShapeToolExecutor w
 
         if (highlight)
         {
-            HighlightSnapAxis(snapXAxis, snapYAxis);
+            HighlightSnapAxis(snapXAxis, snapYAxis, string.IsNullOrEmpty(snapXAxis) && string.IsNullOrEmpty(snapYAxis) ? null : snapped);
         }
 
         if (AlignToPixels)
@@ -345,7 +344,7 @@ internal abstract class DrawableShapeToolExecutor<T> : SimpleShapeToolExecutor w
 
         if (highlight)
         {
-            HighlightSnapAxis(snapXAxis, snapYAxis);
+            HighlightSnapAxis(snapXAxis, snapYAxis, string.IsNullOrEmpty(snapXAxis) && string.IsNullOrEmpty(snapYAxis) ? null : snapped);
         }
 
         if (snapped != VecI.Zero)
@@ -364,11 +363,11 @@ internal abstract class DrawableShapeToolExecutor<T> : SimpleShapeToolExecutor w
         return snapped;
     }
 
-    private void HighlightSnapAxis(string snapXAxis, string snapYAxis)
+    private void HighlightSnapAxis(string snapXAxis, string snapYAxis, VecD? snapPoint)
     {
         document.SnappingHandler.SnappingController.HighlightedXAxis = snapXAxis;
         document.SnappingHandler.SnappingController.HighlightedYAxis = snapYAxis;
-        document.SnappingHandler.SnappingController.HighlightedPoint = null;
+        document.SnappingHandler.SnappingController.HighlightedPoint = snapPoint;
     }
 
     public override void OnSettingsChanged(string name, object value)

+ 23 - 2
src/PixiEditor/ViewModels/Document/DocumentViewModel.cs

@@ -157,6 +157,11 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
     public bool AnySymmetryAxisEnabledBindable =>
         HorizontalSymmetryAxisEnabledBindable || VerticalSymmetryAxisEnabledBindable;
 
+
+    public bool OverlayEventsSuppressed => overlaySuppressors.Count > 0;
+
+    private readonly HashSet<string> overlaySuppressors = new();
+
     private VecI size = new VecI(64, 64);
     public int Width => size.X;
     public int Height => size.Y;
@@ -224,6 +229,7 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
     public AnimationDataViewModel AnimationDataViewModel { get; }
     public TextOverlayViewModel TextOverlayViewModel { get; }
 
+
     public IReadOnlyCollection<IStructureMemberHandler> SoftSelectedStructureMembers => softSelectedStructureMembers;
     private DocumentInternalParts Internals { get; }
     INodeGraphHandler IDocument.NodeGraphHandler => NodeGraph;
@@ -437,7 +443,8 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
             mappedNodeIds.Add(id, guid);
             Guid pairGuid = Guid.Empty;
 
-            if (serializedNode.PairId != null && mappedNodeIds.TryGetValue(serializedNode.PairId.Value, out Guid pairId))
+            if (serializedNode.PairId != null &&
+                mappedNodeIds.TryGetValue(serializedNode.PairId.Value, out Guid pairId))
             {
                 pairGuid = pairId;
             }
@@ -769,6 +776,18 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
         return bitmap.GetSRGBPixel(new VecI((int)transformed.X, (int)transformed.Y));
     }
 
+    public void SuppressAllOverlayEvents(string suppressor)
+    {
+        overlaySuppressors.Add(suppressor);
+        OnPropertyChanged(nameof(OverlayEventsSuppressed));
+    }
+
+    public void RestoreAllOverlayEvents(string suppressor)
+    {
+        overlaySuppressors.Remove(suppressor);
+        OnPropertyChanged(nameof(OverlayEventsSuppressed));
+    }
+
     public Color PickColorFromCanvas(VecI pos, DocumentScope scope, KeyFrameTime frameTime, string? customOutput = null)
     {
         // there is a tiny chance that the image might get disposed by another thread
@@ -778,7 +797,9 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
             // via a passthrough action to avoid all the try catches
             if (scope == DocumentScope.Canvas)
             {
-                using Surface tmpSurface = new Surface(SizeBindable); // new Surface is on purpose, Surface.ForDisplay doesn't work here
+                using Surface
+                    tmpSurface =
+                        new Surface(SizeBindable); // new Surface is on purpose, Surface.ForDisplay doesn't work here
                 Renderer.RenderDocument(tmpSurface.DrawingSurface, frameTime, SizeBindable, customOutput);
 
                 return tmpSurface.GetSrgbPixel(pos);

+ 12 - 0
src/PixiEditor/ViewModels/Tools/Tools/ColorPickerToolViewModel.cs

@@ -170,4 +170,16 @@ internal class ColorPickerToolViewModel : ToolViewModel, IColorPickerHandler
 
     public override void KeyChanged(bool ctrlIsDown, bool shiftIsDown, bool altIsDown, Key argsKey) =>
         UpdateActionDisplay(ctrlIsDown, shiftIsDown);
+
+    protected override void OnSelected(bool restoring)
+    {
+        base.OnSelected(restoring);
+        ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument.SuppressAllOverlayEvents(ToolName);
+    }
+
+    protected override void OnDeselecting(bool transient)
+    {
+        base.OnDeselecting(transient);
+        ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument.RestoreAllOverlayEvents(ToolName);
+    }
 }

+ 7 - 0
src/PixiEditor/ViewModels/Tools/Tools/MoveViewportToolViewModel.cs

@@ -28,5 +28,12 @@ internal class MoveViewportToolViewModel : ToolViewModel
     protected override void OnSelected(bool restoring)
     {
         ActionDisplay = new LocalizedString("MOVE_VIEWPORT_ACTION_DISPLAY");
+        ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument.SuppressAllOverlayEvents(ToolName);
+    }
+
+    protected override void OnDeselecting(bool transient)
+    {
+        base.OnDeselecting(transient);
+        ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument.RestoreAllOverlayEvents(ToolName);
     }
 }

+ 0 - 2
src/PixiEditor/ViewModels/Tools/Tools/VectorEllipseToolViewModel.cs

@@ -60,8 +60,6 @@ internal class VectorEllipseToolViewModel : ShapeTool, IVectorEllipseToolHandler
 
     protected override void OnSelected(bool restoring)
     {
-        if (restoring) return;
-
         ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseVectorEllipseTool();
     }
 

+ 0 - 2
src/PixiEditor/ViewModels/Tools/Tools/VectorLineToolViewModel.cs

@@ -72,8 +72,6 @@ internal class VectorLineToolViewModel : ShapeTool, IVectorLineToolHandler
 
     protected override void OnSelected(bool restoring)
     {
-        if (restoring) return;
-
         var document = ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument;
         document.Tools.UseVectorLineTool();
     }

+ 0 - 2
src/PixiEditor/ViewModels/Tools/Tools/VectorPathToolViewModel.cs

@@ -119,8 +119,6 @@ internal class VectorPathToolViewModel : ShapeTool, IVectorPathToolHandler
     
     protected override void OnSelected(bool restoring)
     {
-        if (restoring) return;
-
         ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseVectorPathTool();
         isActivated = true;
     }

+ 0 - 2
src/PixiEditor/ViewModels/Tools/Tools/VectorRectangleToolViewModel.cs

@@ -73,8 +73,6 @@ internal class VectorRectangleToolViewModel : ShapeTool, IVectorRectangleToolHan
 
     protected override void OnSelected(bool restoring)
     {
-        if (restoring) return;
-
         ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseVectorRectangleTool();
     }
 

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

@@ -69,6 +69,13 @@ internal class ViewportOverlays
         textOverlay = new TextOverlay();
         BindTextOverlay();
 
+        Binding suppressOverlayEventsBinding = new()
+        {
+            Source = Viewport,
+            Path = "Document.OverlayEventsSuppressed",
+            Mode = BindingMode.OneWay
+        };
+
         Viewport.ActiveOverlays.Add(gridLinesOverlay);
         Viewport.ActiveOverlays.Add(referenceLayerOverlay);
         Viewport.ActiveOverlays.Add(selectionOverlay);
@@ -79,6 +86,11 @@ internal class ViewportOverlays
         Viewport.ActiveOverlays.Add(snappingOverlay);
         Viewport.ActiveOverlays.Add(brushShapeOverlay);
         Viewport.ActiveOverlays.Add(textOverlay);
+
+        foreach (var overlay in Viewport.ActiveOverlays)
+        {
+            overlay.Bind(Overlay.SuppressEventsProperty, suppressOverlayEventsBinding);
+        }
     }
 
     private void BindReferenceLayerOverlay()

+ 20 - 1
src/PixiEditor/Views/Overlays/Overlay.cs

@@ -57,6 +57,18 @@ public abstract class Overlay : Decorator, IOverlay // TODO: Maybe make it not a
     public Handle? CapturedHandle { get; set; } = null!;
     public VecD PointerPosition { get; internal set; }
 
+    public static readonly StyledProperty<bool> SuppressEventsProperty = AvaloniaProperty.Register<Overlay, bool>(
+        nameof(SuppressEvents));
+
+    public bool SuppressEvents
+    {
+        get => GetValue(SuppressEventsProperty);
+        set
+        {
+            SetValue(SuppressEventsProperty, value);
+        }
+    }
+
     private readonly Dictionary<AvaloniaProperty, OverlayTransition> activeTransitions = new();
 
     private DispatcherTimer? transitionTimer;
@@ -99,6 +111,7 @@ public abstract class Overlay : Decorator, IOverlay // TODO: Maybe make it not a
 
     public void EnterPointer(OverlayPointerArgs args)
     {
+        if(SuppressEvents) return;
         OnOverlayPointerEntered(args);
         if (args.Handled) return;
         InvokeHandleEvent(HandleEventType.PointerEnteredOverlay, args);
@@ -108,6 +121,7 @@ public abstract class Overlay : Decorator, IOverlay // TODO: Maybe make it not a
 
     public void ExitPointer(OverlayPointerArgs args)
     {
+        if(SuppressEvents) return;
         OnOverlayPointerExited(args);
         if (args.Handled) return;
         InvokeHandleEvent(HandleEventType.PointerExitedOverlay, args);
@@ -117,6 +131,7 @@ public abstract class Overlay : Decorator, IOverlay // TODO: Maybe make it not a
 
     public void MovePointer(OverlayPointerArgs args)
     {
+        if(SuppressEvents) return;
         InvokeHandleEvent(HandleEventType.PointerMovedOverlay, args);
         if (args.Handled) return;
         OnOverlayPointerMoved(args);
@@ -138,6 +153,7 @@ public abstract class Overlay : Decorator, IOverlay // TODO: Maybe make it not a
 
     public void PressPointer(OverlayPointerArgs args)
     {
+        if(SuppressEvents) return;
         InvokeHandleEvent(HandleEventType.PointerPressedOverlay, args);
         if (args.Handled) return;
         OnOverlayPointerPressed(args);
@@ -147,6 +163,7 @@ public abstract class Overlay : Decorator, IOverlay // TODO: Maybe make it not a
 
     public void ReleasePointer(OverlayPointerArgs args)
     {
+        if(SuppressEvents) return;
         InvokeHandleEvent(HandleEventType.PointerReleasedOverlay, args);
         if (args.Handled)
         {
@@ -165,19 +182,21 @@ public abstract class Overlay : Decorator, IOverlay // TODO: Maybe make it not a
     
     public void KeyPressed(KeyEventArgs args)
     {
+        if(SuppressEvents) return;
         OnKeyPressed(args.Key, args.KeyModifiers, args.KeySymbol);
         KeyPressedOverlay?.Invoke(args.Key, args.KeyModifiers);
     }
 
     public void KeyReleased(KeyEventArgs keyEventArgs)
     {
+        if(SuppressEvents) return;
         OnKeyReleased(keyEventArgs.Key, keyEventArgs.KeyModifiers);
         KeyReleasedOverlay?.Invoke(keyEventArgs.Key, keyEventArgs.KeyModifiers);
     }
 
     public virtual bool TestHit(VecD point)
     {
-        return Handles.Any(handle => handle.IsWithinHandle(handle.Position, new VecD(point.X, point.Y), ZoomScale));
+        return !SuppressEvents && Handles.Any(handle => handle.IsWithinHandle(handle.Position, new VecD(point.X, point.Y), ZoomScale));
     }
 
     public void AddHandle(Handle handle)

+ 1 - 1
src/PixiEditor/Views/Overlays/SnappingOverlay.cs

@@ -53,7 +53,7 @@ internal class SnappingOverlay : Overlay
 
     public override void RenderOverlay(Canvas context, RectD canvasBounds)
     {
-        if (SnappingController is null)
+        if (SnappingController is null || SuppressEvents)
         {
             return;
         }

+ 7 - 2
src/PixiEditor/Views/Overlays/TransformOverlay/TransformOverlay.cs

@@ -902,9 +902,9 @@ internal class TransformOverlay : Overlay
                 InternalState.ProportionalAngle2, cornersOnStartAnchorDrag, targetPos,
                 ScaleFromCenter,
                 SnappingController,
-                out string snapX, out string snapY, out VecD? snapPoint);
+                out string snapX, out string snapY);
 
-            HighlightSnappedAxis(snapX, snapY, snapPoint);
+            VecD? snapPoint = null;
 
             if (newCorners is not null)
             {
@@ -917,8 +917,13 @@ internal class TransformOverlay : Overlay
                     : (ShapeCorners)newCorners;
 
                 Corners = (ShapeCorners)newCorners;
+                if (!string.IsNullOrEmpty(snapX) || !string.IsNullOrEmpty(snapY))
+                {
+                    snapPoint = TransformHelper.GetAnchorPosition((ShapeCorners)newCorners, (Anchor)capturedAnchor);
+                }
             }
 
+            HighlightSnappedAxis(snapX, snapY, snapPoint);
             UpdateOriginPos();
         }
         else if (TransformHelper.IsSide((Anchor)capturedAnchor))

+ 1 - 7
src/PixiEditor/Views/Overlays/TransformOverlay/TransformUpdateHelper.cs

@@ -13,7 +13,7 @@ internal static class TransformUpdateHelper
     public static ShapeCorners? UpdateShapeFromCorner
     (Anchor targetCorner, TransformCornerFreedom freedom, double propAngle1, double propAngle2, ShapeCorners corners,
         VecD desiredPos, bool scaleFromCenter,
-        SnappingController? snappingController, out string snapX, out string snapY, out VecD? snapPoint)
+        SnappingController? snappingController, out string snapX, out string snapY)
     {
         if (!TransformHelper.IsCorner(targetCorner))
             throw new ArgumentException($"{targetCorner} is not a corner");
@@ -21,7 +21,6 @@ internal static class TransformUpdateHelper
         if (freedom == TransformCornerFreedom.Locked)
         {
             snapX = snapY = "";
-            snapPoint = null;
             return corners;
         }
 
@@ -33,7 +32,6 @@ internal static class TransformUpdateHelper
             VecD oppositePos = TransformHelper.GetAnchorPosition(corners, opposite);
 
             snapX = snapY = "";
-            snapPoint = null;
 
             // constrain desired pos to a "propotional" diagonal line if needed
             if (freedom == TransformCornerFreedom.ScaleProportionally && corners.IsRect)
@@ -45,7 +43,6 @@ internal static class TransformUpdateHelper
                 if (snappingController is not null)
                 {
                     desiredPos = snappingController.GetSnapPoint(desiredPos, direction, out snapX, out snapY);
-                    snapPoint = string.IsNullOrEmpty(snapX) && string.IsNullOrEmpty(snapY) ? null : desiredPos;
                 }
             }
             else if (freedom == TransformCornerFreedom.ScaleProportionally)
@@ -56,7 +53,6 @@ internal static class TransformUpdateHelper
                 if (snappingController is not null)
                 {
                     desiredPos = snappingController.GetSnapPoint(desiredPos, direction, out snapX, out snapY);
-                    snapPoint = string.IsNullOrEmpty(snapX) && string.IsNullOrEmpty(snapY) ? null : desiredPos;
                 }
             }
             else
@@ -64,7 +60,6 @@ internal static class TransformUpdateHelper
                 if (snappingController is not null)
                 {
                     desiredPos = snappingController.GetSnapPoint(desiredPos, out snapX, out snapY);
-                    snapPoint = string.IsNullOrEmpty(snapX) && string.IsNullOrEmpty(snapY) ? null : desiredPos;
                 }
             }
 
@@ -143,7 +138,6 @@ internal static class TransformUpdateHelper
         if (freedom == TransformCornerFreedom.Free)
         {
             snapX = snapY = "";
-            snapPoint = null;
             ShapeCorners newCorners = TransformHelper.UpdateCorner(corners, targetCorner, desiredPos);
             return newCorners.IsLegal ? newCorners : null;
         }

+ 1 - 0
src/PixiEditor/Views/Rendering/Scene.cs

@@ -305,6 +305,7 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
                 }
 
                 overlay.PointerPosition = lastMousePosition;
+
                 overlay.ZoomScale = Scale;
 
                 if (!overlay.CanRender()) continue;