Browse Source

Improved snapping overlay

Krzysztof Krysiński 4 months ago
parent
commit
c91e8f8e5c

+ 18 - 18
src/PixiEditor/Models/Controllers/InputDevice/SnappingController.cs

@@ -16,8 +16,8 @@ public class SnappingController
     /// </summary>
     public double SnapDistance { get; set; } = DefaultSnapDistance;
 
-    public Dictionary<string, Func<double>> HorizontalSnapPoints { get; } = new();
-    public Dictionary<string, Func<double>> VerticalSnapPoints { get; } = new();
+    public Dictionary<string, Func<VecD>> HorizontalSnapPoints { get; } = new();
+    public Dictionary<string, Func<VecD>> VerticalSnapPoints { get; } = new();
 
     public string HighlightedXAxis
     {
@@ -84,12 +84,12 @@ public class SnappingController
         }
 
         snapAxis = HorizontalSnapPoints.First().Key;
-        double closest = HorizontalSnapPoints.First().Value();
+        double closest = HorizontalSnapPoints.First().Value().X;
         foreach (var snapPoint in HorizontalSnapPoints)
         {
-            if (Math.Abs(snapPoint.Value() - xPos) < Math.Abs(closest - xPos))
+            if (Math.Abs(snapPoint.Value().X - xPos) < Math.Abs(closest - xPos))
             {
-                closest = snapPoint.Value();
+                closest = snapPoint.Value().X;
                 snapAxis = snapPoint.Key;
             }
         }
@@ -118,12 +118,12 @@ public class SnappingController
         }
 
         snapAxisKey = VerticalSnapPoints.First().Key;
-        double closest = VerticalSnapPoints.First().Value();
+        double closest = VerticalSnapPoints.First().Value().Y;
         foreach (var snapPoint in VerticalSnapPoints)
         {
-            if (Math.Abs(snapPoint.Value() - yPos) < Math.Abs(closest - yPos))
+            if (Math.Abs(snapPoint.Value().Y - yPos) < Math.Abs(closest - yPos))
             {
-                closest = snapPoint.Value();
+                closest = snapPoint.Value().Y;
                 snapAxisKey = snapPoint.Key;
             }
         }
@@ -139,20 +139,20 @@ public class SnappingController
 
     public void AddXYAxis(string identifier, VecD axisVector)
     {
-        HorizontalSnapPoints[identifier] = () => axisVector.X;
-        VerticalSnapPoints[identifier] = () => axisVector.Y;
+        HorizontalSnapPoints[identifier] = () => axisVector;
+        VerticalSnapPoints[identifier] = () => axisVector;
     }
 
     public void AddBounds(string identifier, Func<RectD> tightBounds)
     {
-        HorizontalSnapPoints[$"{identifier}.center"] = () => tightBounds().Center.X;
-        VerticalSnapPoints[$"{identifier}.center"] = () => tightBounds().Center.Y;
+        HorizontalSnapPoints[$"{identifier}.center"] = () => tightBounds().Center;
+        VerticalSnapPoints[$"{identifier}.center"] = () => tightBounds().Center;
 
-        HorizontalSnapPoints[$"{identifier}.left"] = () => tightBounds().Left;
-        VerticalSnapPoints[$"{identifier}.top"] = () => tightBounds().Top;
+        HorizontalSnapPoints[$"{identifier}.left"] = () => tightBounds().TopLeft;
+        VerticalSnapPoints[$"{identifier}.top"] = () => tightBounds().TopRight;
 
-        HorizontalSnapPoints[$"{identifier}.right"] = () => tightBounds().Right;
-        VerticalSnapPoints[$"{identifier}.bottom"] = () => tightBounds().Bottom;
+        HorizontalSnapPoints[$"{identifier}.right"] = () => tightBounds().BottomRight;
+        VerticalSnapPoints[$"{identifier}.bottom"] = () => tightBounds().BottomLeft;
     }
 
     /// <summary>
@@ -373,8 +373,8 @@ public class SnappingController
 
     public void AddXYAxis(string identifier, Func<VecD> pointFunc)
     {
-        HorizontalSnapPoints[identifier] = () => pointFunc().X;
-        VerticalSnapPoints[identifier] = () => pointFunc().Y;
+        HorizontalSnapPoints[identifier] = pointFunc;
+        VerticalSnapPoints[identifier] = pointFunc;
     }
     
     private bool IsWithinSnapDistance(VecD snapPoint, VecD pos)

+ 42 - 4
src/PixiEditor/Views/Overlays/SnappingOverlay.cs

@@ -1,10 +1,13 @@
-using Avalonia;
+using System.Globalization;
+using Avalonia;
 using Avalonia.Media;
 using Avalonia.Styling;
 using Drawie.Backend.Core.Surfaces;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
+using Drawie.Backend.Core.Text;
 using PixiEditor.Models.Controllers.InputDevice;
 using Drawie.Numerics;
+using PixiEditor.Extensions.UI.Overlays;
 using PixiEditor.Helpers;
 using Colors = Drawie.Backend.Core.ColorsImpl.Colors;
 using Point = Avalonia.Point;
@@ -25,6 +28,10 @@ internal class SnappingOverlay : Overlay
     private Paint horizontalAxisPen;
     private Paint verticalAxisPen; 
     private Paint previewPointPen;
+    private VecD lastMousePosition;
+
+    private Paint distanceTextPaint;
+    private Font distanceFont = Font.CreateDefault();
 
     private const float startSize = 1;
     
@@ -39,7 +46,9 @@ internal class SnappingOverlay : Overlay
         /*TODO: Theme variant is not present, that's why Dark is hardcoded*/        
         horizontalAxisPen = ResourceLoader.GetPaint("HorizontalSnapAxisBrush", PaintStyle.Stroke, ThemeVariant.Dark) ?? new Paint() { Color = Colors.Red, Style = PaintStyle.Stroke, IsAntiAliased = true, StrokeWidth = startSize};
         verticalAxisPen = ResourceLoader.GetPaint("VerticalSnapAxisBrush", PaintStyle.Stroke, ThemeVariant.Dark) ?? new Paint() { Color = Colors.Green, Style = PaintStyle.Stroke, IsAntiAliased = true, StrokeWidth = startSize}; 
-        previewPointPen = ResourceLoader.GetPaint("SnapPointPreviewBrush", PaintStyle.Fill, ThemeVariant.Dark) ?? new Paint() { Color = Colors.Blue, Style = PaintStyle.Stroke, IsAntiAliased = true, StrokeWidth = startSize}; 
+        previewPointPen = ResourceLoader.GetPaint("SnapPointPreviewBrush", PaintStyle.Fill, ThemeVariant.Dark) ?? new Paint() { Color = Colors.Blue, Style = PaintStyle.Stroke, IsAntiAliased = true, StrokeWidth = startSize};
+        distanceTextPaint = new Paint() { Color = Colors.White, Style = PaintStyle.Fill, IsAntiAliased = true, StrokeWidth = startSize };
+
         IsHitTestVisible = false;
     }
 
@@ -50,13 +59,18 @@ internal class SnappingOverlay : Overlay
             return;
         }
 
+        VecD mousePoint = SnappingController.HighlightedPoint ?? lastMousePosition;
+
         if (!string.IsNullOrEmpty(SnappingController.HighlightedXAxis))
         {
             foreach (var snapPoint in SnappingController.HorizontalSnapPoints)
             {
                 if (snapPoint.Key == SnappingController.HighlightedXAxis)
                 {
-                    context.DrawLine(new VecD(snapPoint.Value(), 0), new VecD(snapPoint.Value(), canvasBounds.Height), horizontalAxisPen);
+                    VecD snapPointValue = snapPoint.Value();
+                    context.DrawLine(new VecD(snapPointValue.X, mousePoint.Y), new VecD(snapPointValue.X, snapPointValue.Y), horizontalAxisPen);
+
+                    DrawDistanceText(context, snapPointValue + new VecD(10 / ZoomScale, 0), mousePoint);
                 }
             }
         }
@@ -67,7 +81,10 @@ internal class SnappingOverlay : Overlay
             {
                 if (snapPoint.Key == SnappingController.HighlightedYAxis)
                 {
-                    context.DrawLine(new VecD(0, snapPoint.Value()), new VecD(canvasBounds.Width, snapPoint.Value()), verticalAxisPen);
+                    var snapPointValue = snapPoint.Value();
+                    context.DrawLine(new VecD(mousePoint.X, snapPointValue.Y), new VecD(snapPointValue.X, snapPointValue.Y), verticalAxisPen);
+
+                    DrawDistanceText(context, snapPointValue + new VecD(0, -10 / ZoomScale), mousePoint);
                 }
             }
         }
@@ -78,6 +95,27 @@ internal class SnappingOverlay : Overlay
         }
     }
 
+    private void DrawDistanceText(Canvas context, VecD snapPointValue, VecD mousePoint)
+    {
+        VecD distance = snapPointValue - mousePoint;
+        VecD center = (snapPointValue + mousePoint) / 2;
+        distanceFont.Size = 12 / (float)ZoomScale;
+
+        distanceTextPaint.Color = Colors.Black;
+        distanceTextPaint.Style = PaintStyle.Stroke;
+        distanceTextPaint.StrokeWidth = 2f / (float)ZoomScale;
+
+        context.DrawText($"{distance.Length.ToString("F2", CultureInfo.CurrentCulture)} px", center, distanceFont, distanceTextPaint);
+        distanceTextPaint.Color = Colors.White;
+        distanceTextPaint.Style = PaintStyle.Fill;
+        context.DrawText($"{distance.Length.ToString("F2", CultureInfo.CurrentCulture)} px", center, distanceFont, distanceTextPaint);
+    }
+
+    protected override void OnOverlayPointerMoved(OverlayPointerArgs args)
+    {
+        lastMousePosition = args.Point;
+    }
+
     protected override void ZoomChanged(double newZoom)
     {
         horizontalAxisPen.StrokeWidth = startSize / (float)newZoom;