瀏覽代碼

SelectionOverlay

flabbet 10 月之前
父節點
當前提交
bb167f1f69

+ 2 - 1
src/PixiEditor/Animation/Animators.cs

@@ -1,5 +1,6 @@
 using Avalonia.Media;
 using Avalonia.Styling;
+using Drawie.Backend.Core.Surfaces.Vector;
 
 namespace PixiEditor.Animation;
 
@@ -7,6 +8,6 @@ public class Animators : Styles
 {
     public Animators(IServiceProvider? sp = null)
     {
-        Avalonia.Animation.Animation.RegisterCustomAnimator<IDashStyle, SelectionDashAnimator>();
+        Avalonia.Animation.Animation.RegisterCustomAnimator<IDashPathEffect, SelectionDashAnimator>();
     }
 }

+ 26 - 0
src/PixiEditor/Animation/IDashPathEffect.cs

@@ -0,0 +1,26 @@
+using Drawie.Backend.Core.Surfaces.Vector;
+
+namespace PixiEditor.Animation;
+
+public interface IDashPathEffect
+{
+    public IReadOnlyList<float> Dashes { get; set; }
+    public float Phase { get; set; }
+    public PathEffect ToPathEffect();
+}
+
+public class DashPathEffect : IDashPathEffect
+{
+    public IReadOnlyList<float> Dashes { get; set; }
+    public float Phase { get; set; }
+
+    public DashPathEffect(IReadOnlyList<float> dashes, float phase)
+    {
+        Dashes = dashes;
+        Phase = phase;
+    }
+    public PathEffect ToPathEffect()
+    {
+        return PathEffect.CreateDash(Dashes.ToArray(), Phase);
+    }
+}

+ 7 - 5
src/PixiEditor/Animation/SelectionDashAnimator.cs

@@ -1,18 +1,20 @@
 using Avalonia.Animation;
 using Avalonia.Media;
+using Drawie.Backend.Core.Surfaces.Vector;
 
 namespace PixiEditor.Animation;
 
-public sealed class SelectionDashAnimator : InterpolatingAnimator<IDashStyle>
+public sealed class SelectionDashAnimator : InterpolatingAnimator<IDashPathEffect>
 {
-    public override IDashStyle Interpolate(double progress, IDashStyle oldValue, IDashStyle newValue)
+    
+    public override IDashPathEffect Interpolate(double progress, IDashPathEffect oldValue, IDashPathEffect newValue)
     {
-        return new DashStyle(oldValue.Dashes, progress * 6);
+        return new DashPathEffect(oldValue.Dashes.ToArray(), (float)progress * 6);
     }
 
-    public static IDashStyle Interpolate(double progress, int steps, double[] dashes)
+    public static IDashPathEffect Interpolate(double progress, int steps, float[] dashes)
     {
-        var newDashStyle = new DashStyle(dashes, progress * steps);
+        var newDashStyle = new DashPathEffect(dashes, (float)progress * steps);
         return newDashStyle;
     }
 }

+ 70 - 32
src/PixiEditor/Views/Overlays/SelectionOverlay/SelectionOverlay.cs

@@ -7,8 +7,12 @@ using Avalonia.Styling;
 using PixiEditor.Animation;
 using Drawie.Backend.Core.Numerics;
 using Drawie.Backend.Core.Surfaces;
+using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Backend.Core.Surfaces.Vector;
 using Drawie.Numerics;
+using PixiEditor.Helpers.Extensions;
+using Color = Drawie.Backend.Core.ColorsImpl.Color;
+using Colors = Drawie.Backend.Core.ColorsImpl.Colors;
 
 namespace PixiEditor.Views.Overlays.SelectionOverlay;
 #nullable enable
@@ -32,89 +36,120 @@ internal class SelectionOverlay : Overlay
         set => SetValue(ShowFillProperty, value);
     }
 
-    public static readonly DirectProperty<SelectionOverlay, IDashStyle> BlackDashedPenProperty =
-        AvaloniaProperty.RegisterDirect<SelectionOverlay, IDashStyle>("BlackDashedPen",
-            overlay => overlay.blackDashedPen.DashStyle,
-            (overlay, pen) => overlay.blackDashedPen.DashStyle = pen);
+    public static readonly DirectProperty<SelectionOverlay, IDashPathEffect> BlackDashedPenProperty =
+        AvaloniaProperty.RegisterDirect<SelectionOverlay, IDashPathEffect>("BlackDashedPen",
+            overlay => overlay.blackDashedPenEffect,
+            (overlay, pen) =>
+            {
+                overlay.blackDashedPenEffect = pen;
+                try
+                {
+                    overlay.blackDashedPen.PathEffect = pen.ToPathEffect();
+                }
+                catch
+                {
+                    
+                }
+            });
 
     static SelectionOverlay()
     {
         AffectsRender<SelectionOverlay>(PathProperty);
-        ShowFillProperty.Changed.Subscribe(OnShowFillChanged);
         PathProperty.Changed.Subscribe(OnPathChanged);
     }
 
-    private Pen whitePen = new Pen(Brushes.White, 1);
-    private Pen blackDashedPen = new Pen(Brushes.Black, 1) { DashStyle = startingFrame };
-    private Brush fillBrush = new SolidColorBrush(Color.FromArgb(80, 0, 80, 255));
+    private Paint whitePaint = new Paint() { Color = Colors.White, IsAntiAliased = true, StrokeWidth = 1, Style = PaintStyle.Stroke };
+
+    private Paint blackDashedPen = new Paint
+    {
+        Color = Colors.Black, StrokeWidth = 1, IsAntiAliased = true, Style = PaintStyle.Stroke,
+    };
+    
+    private IDashPathEffect blackDashedPenEffect = new DashPathEffect(new float[] { 2, 4 }, 0);
+
+    private Paint fillBrush = new Paint() { Color = Color.FromArgb(80, 0, 80, 255), IsAntiAliased = true, Style = PaintStyle.Fill };
 
-    private static DashStyle startingFrame = new DashStyle(new double[] { 2, 4 }, 0);
+    private static DashPathEffect startingFrame;
 
-    private Geometry renderPath = new PathGeometry();
+    private VectorPath renderPath; 
     private Avalonia.Animation.Animation animation;
     private CancellationTokenSource cancelAnimationToken;
+    private bool isAnimating;
 
     public SelectionOverlay()
     {
         IsHitTestVisible = false;
 
-        if (Application.Current.Styles.TryGetResource("SelectionFillBrush", Application.Current.ActualThemeVariant, out var fillBrush))
+        if (Application.Current.Styles.TryGetResource("SelectionFillBrush", Application.Current.ActualThemeVariant,
+                out var fillBrush))
         {
-            this.fillBrush = (Brush)fillBrush;
+            if (fillBrush is SolidColorBrush solidColorBrush)
+            {
+                this.fillBrush = new Paint() { Color = solidColorBrush.Color.ToColor(), IsAntiAliased = true };
+            }
         }
 
+        blackDashedPen.PathEffect = blackDashedPenEffect.ToPathEffect();
+
         animation = new Avalonia.Animation.Animation()
         {
-            Duration = new TimeSpan(0, 0, 0, 2, 0),
-            IterationCount = IterationCount.Infinite,
+            Duration = new TimeSpan(0, 0, 0, 2, 0), IterationCount = IterationCount.Infinite,
         };
-
+        
         int steps = 7;
         float step = 1f / steps;
 
         for (int i = 0; i < steps; i++)
         {
             Cue cue = new Cue(i * step);
+            Pen pen;
             animation.Children.Add(new KeyFrame()
             {
                 Cue = cue,
-                Setters = { new Setter(BlackDashedPenProperty, SelectionDashAnimator.Interpolate(cue.CueValue, 6, blackDashedPen.DashStyle.Dashes.ToArray())) }
+                Setters =
+                {
+                    new Setter(BlackDashedPenProperty, SelectionDashAnimator.Interpolate(cue.CueValue, 6, blackDashedPenEffect.Dashes.ToArray()))
+                }
             });
         }
     }
 
     public override void RenderOverlay(Canvas context, RectD canvasBounds)
     {
-        /*base.Render(context);
+        if (isAnimating)
+        {
+            Refresh();
+        }
+        
         if (Path is null)
             return;
 
         try
         {
-            renderPath = new PathGeometry()
-            {
-                FillRule = FillRule.EvenOdd,
-                Figures = (PathFigures?)PathFigures.Parse(Path.ToSvgPathData()),
-            };
+            renderPath = new VectorPath(Path);
+            renderPath.FillType = PathFillType.EvenOdd;
         }
         catch (FormatException)
         {
             return;
         }
-        context.DrawGeometry(null, whitePen, renderPath);
-        context.DrawGeometry(fillBrush, blackDashedPen, renderPath);*/
-    }
 
-    protected override void ZoomChanged(double newZoom)
-    {
-        whitePen.Thickness = 1.0 / newZoom;
-        blackDashedPen.Thickness = 1.0 / newZoom;
+        context.DrawPath(renderPath, whitePaint);
+        if (ShowFill)
+        {
+            context.DrawPath(renderPath, fillBrush);
+        }
+
+        blackDashedPen.PathEffect?.Dispose();
+        float finalScale = Math.Min((float)ZoomScale, 20f);
+        blackDashedPen.PathEffect = PathEffect.CreateDash(blackDashedPenEffect.Dashes.Select(d => d / finalScale).ToArray(), blackDashedPenEffect.Phase);
+        context.DrawPath(renderPath, blackDashedPen);
     }
 
-    private static void OnShowFillChanged(AvaloniaPropertyChangedEventArgs<bool> args)
+    protected override void ZoomChanged(double newZoom)
     {
-        var self = (SelectionOverlay)args.Sender;
-        self.fillBrush.Opacity = args.NewValue.Value ? 1 : 0;
+        whitePaint.StrokeWidth = 1.0f / (float)newZoom;
+        blackDashedPen.StrokeWidth = 1.0f / (float)newZoom;
     }
 
     private static void OnPathChanged(AvaloniaPropertyChangedEventArgs<VectorPath?> args)
@@ -124,9 +159,12 @@ internal class SelectionOverlay : Overlay
         {
             self.cancelAnimationToken = new CancellationTokenSource();
             self.animation.RunAsync(self, self.cancelAnimationToken.Token);
+            self.isAnimating = true;
+            self.Refresh();
         }
         else if (self.cancelAnimationToken != null)
         {
+            self.isAnimating = false;
             self.cancelAnimationToken.Cancel();
         }
     }