Files
WCS/Plugins/Wcs/Plugin.Cowain.Wcs/Controls/RgvArrowDecorator.cs
2026-03-02 09:13:29 +08:00

117 lines
3.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.VisualTree;
namespace Plugin.Cowain.Wcs.Controls;
public class RgvArrowDecorator : Decorator
{
public static readonly StyledProperty<Point> ArrowEndCanvasPointProperty =
AvaloniaProperty.Register<RgvArrowDecorator, Point>(nameof(ArrowEndCanvasPoint));
public Point ArrowEndCanvasPoint
{
get => GetValue(ArrowEndCanvasPointProperty);
set => SetValue(ArrowEndCanvasPointProperty, value);
}
public static readonly StyledProperty<IBrush> ArrowBrushProperty =
AvaloniaProperty.Register<RgvArrowDecorator, IBrush>(nameof(ArrowBrush), Brushes.Red);
public IBrush ArrowBrush
{
get => GetValue(ArrowBrushProperty);
set => SetValue(ArrowBrushProperty, value);
}
public static readonly StyledProperty<bool> ArrowDirectionProperty =
AvaloniaProperty.Register<RgvArrowDecorator, bool>(nameof(ArrowDirection), false);
public bool ArrowDirection
{
get => GetValue(ArrowDirectionProperty);
set => SetValue(ArrowDirectionProperty, value);
}
public RgvArrowDecorator()
{
this.LayoutUpdated += (s, e) => this.InvalidateVisual();
ArrowEndCanvasPointProperty.Changed.AddClassHandler<RgvArrowDecorator>((b, e) => b.InvalidateVisual());
ArrowBrushProperty.Changed.AddClassHandler<RgvArrowDecorator>((b, e) => b.InvalidateVisual());
ArrowDirectionProperty.Changed.AddClassHandler<RgvArrowDecorator>((b, e) => b.InvalidateVisual());
}
public override void Render(DrawingContext context)
{
base.Render(context);
var start = new Point(Bounds.Width / 2, Bounds.Height / 2);
var endCanvas = ArrowEndCanvasPoint;
var canvas = this.FindAncestorOfType<Canvas>();
if (canvas == null)
return;
var transform = this.TransformToVisual(canvas);
Point myLeftTop = default;
if (transform != null)
{
if (transform is Matrix matrix)
myLeftTop = matrix.Transform(new Point(0, 0));
}
// 转换为本地坐标
var end = new Point(endCanvas.X - myLeftTop.X, endCanvas.Y - myLeftTop.Y);
// 计算三段折线
double offset = 15; // 垂直偏移
bool isAbove = end.Y < start.Y;
// 第一拐点:起点垂直偏移
var first = new Point(start.X, start.Y + (isAbove ? -offset : offset));
// 第二拐点目标X起点Y偏移
var second = new Point(end.X, end.Y + (isAbove ? offset : -offset));
// 终点:目标点
var last = new Point(end.X, end.Y);
// 画三段折线
var pen = new Pen(ArrowBrush, 2);
context.DrawLine(pen, start, first);
context.DrawLine(pen, first, second);
context.DrawLine(pen, second, last);
// 画箭头头部
if (ArrowDirection)
{
DrawArrowHead(context, end, second, ArrowBrush);
}
else
{
DrawArrowHead(context, second, end, ArrowBrush);
}
}
private void DrawArrowHead(DrawingContext context, Point from, Point to, IBrush brush)
{
// 箭头头部为V型
double arrowSize = 10;
double angle = Math.Atan2(to.Y - from.Y, to.X - from.X);
double leftAngle = angle + Math.PI / 6;
double rightAngle = angle - Math.PI / 6;
var left = new Point(
to.X - arrowSize * Math.Cos(leftAngle),
to.Y - arrowSize * Math.Sin(leftAngle));
var right = new Point(
to.X - arrowSize * Math.Cos(rightAngle),
to.Y - arrowSize * Math.Sin(rightAngle));
var pen = new Pen(brush, 2);
context.DrawLine(pen, to, left);
context.DrawLine(pen, to, right);
}
}