|
@@ -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();
|
|
|
}
|
|
|
}
|