修改了很多

This commit is contained in:
fengjiayi
2024-10-27 00:54:10 +08:00
parent 6f26d303e4
commit cb2553ac69
66 changed files with 2215 additions and 1402 deletions

View File

@@ -28,10 +28,12 @@ namespace Serein.Workbench.Node.View
Semicircle,
}
/// <summary>
/// 贝塞尔曲线
/// </summary>
public class BezierLine : Shape
public class ConnectionLineShape : Shape
{
private readonly double strokeThickness;
@@ -40,28 +42,44 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 确定起始坐标和目标坐标、外光样式的曲线
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <param name="brush"></param>
/// <param name="strokeThickness"></param>
public BezierLine(LineType lineType, Point start, Point end, Brush brush, double strokeThickness = 4)
/// <param name="lineType">线条类型</param>
/// <param name="start">起始坐标</param>
/// <param name="end">结束坐标</param>
/// <param name="brush">颜色</param>
/// <param name="isDotted">是否为虚线</param>
public ConnectionLineShape(LineType lineType,
Point start,
Point end,
Brush brush,
bool isDotted = false,
bool isTop = false)
{
this.lineType = lineType;
this.brush = brush;
startPoint = start;
endPoint = end;
this.strokeThickness = strokeThickness;
InitElementPoint();
this.strokeThickness = 4;
InitElementPoint(isDotted, isTop);
InvalidateVisual(); // 触发重绘
}
public void InitElementPoint()
public void InitElementPoint(bool isDotted , bool isTop = false)
{
hitVisiblePen = new Pen(Brushes.Transparent, 1.0); // 初始化碰撞检测线
hitVisiblePen.Freeze(); // Freeze以提高性能
visualPen = new Pen(brush, 3.0); // 默认可视化Pen
if (isDotted)
{
visualPen.DashStyle = DashStyles.Dash; // 选择虚线样式
}
visualPen.Freeze(); // Freeze以提高性能
linkSize = 4; // 整线条粗细
Panel.SetZIndex(this, -9999999); // 置底
int zIndex = -999999;
if (isTop)
{
zIndex *= -1;
}
Panel.SetZIndex(this, zIndex); // 置底
}
/// <summary>
@@ -104,16 +122,17 @@ namespace Serein.Workbench.Node.View
switch (this.lineType)
{
case LineType.Bezier:
DrawBezierCurve(drawingContext, startPoint, endPoint, linkSize);
DrawBezierCurve(drawingContext, startPoint, endPoint);
break;
case LineType.Semicircle:
DrawBezierCurve(drawingContext, startPoint, endPoint);
DrawSemicircleCurve(drawingContext, startPoint, endPoint);
break;
default:
break;
}
}
#region
private readonly StreamGeometry streamGeometry = new StreamGeometry();
private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心
@@ -125,8 +144,12 @@ namespace Serein.Workbench.Node.View
private Brush brush; // 线条颜色
double linkSize; // 根据缩放比例调整线条粗细
protected override Geometry DefiningGeometry => streamGeometry;
#region
public void UpdateLineColor(Brush brush)
{
visualPen = new Pen(brush, 3.0); // 默认可视化Pen
InvalidateVisual(); // 触发重绘
}
private Point c0, c1; // 用于计算贝塞尔曲线控制点逻辑
@@ -134,15 +157,10 @@ namespace Serein.Workbench.Node.View
private Vector startToEnd;
private void DrawBezierCurve(DrawingContext drawingContext,
Point start,
Point end,
double linkSize,
bool isHitTestVisible = false,
double strokeThickness = 1.0,
bool isMouseOver = false,
double dashOffset = 0.0)
Point end)
{
// 控制点的计算逻辑
double power = 100; // 控制贝塞尔曲线的“拉伸”强度
double power = 140; // 控制贝塞尔曲线的“拉伸”强度
// 计算轴向向量与起点到终点的向量
//var axis = new Vector(1, 0);
@@ -165,31 +183,16 @@ namespace Serein.Workbench.Node.View
context.BeginFigure(start, true, false); // 曲线起点
context.BezierTo(c0, c1, end, true, false); // 画贝塞尔曲线
}
drawingContext.DrawGeometry(null, visualPen, streamGeometry);
// 绘制碰撞检测线
//if (true)
//{
// //hitVisiblePen = new Pen(Brushes.Transparent, linkSize + strokeThickness);
// //hitVisiblePen.Freeze();
// drawingContext.DrawGeometry(null, hitVisiblePen, streamGeometry);
//}
//else
//{
//}
}
#endregion
private void DrawBezierCurve(DrawingContext drawingContext, Point start, Point end)
private void DrawSemicircleCurve(DrawingContext drawingContext, Point start, Point end)
{
// 计算中心点和半径
// 计算圆心和半径
double x = 35 ;
double x = 35;
// 创建一个弧线路径
streamGeometry.Clear();
using (var context = streamGeometry.Open())
@@ -216,6 +219,7 @@ namespace Serein.Workbench.Node.View
drawingContext.DrawGeometry(null, visualPen, streamGeometry);
}
#endregion
}

View File

@@ -4,6 +4,7 @@ using System;
using System.Net;
using System.Reflection;
using System.Windows;
using Serein.Workbench.Extension;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
@@ -16,18 +17,20 @@ namespace Serein.Workbench.Node.View
public abstract class JunctionControlBase : Shape
{
protected JunctionControlBase()
{
this.Width = 25;
this.Height = 20;
this.MouseDown += ControlPointBase_MouseDown;
this.MouseMove += ControlPointBase_MouseMove;
this.MouseDown += JunctionControlBase_MouseDown;
this.MouseMove += JunctionControlBase_MouseMove;
this.MouseLeave += JunctionControlBase_MouseLeave; ;
}
#region
public static readonly DependencyProperty NodeProperty =
DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(JunctionControlBase), new PropertyMetadata(default(NodeModelBase)));
DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(JunctionControlBase), new PropertyMetadata(default(NodeModelBase)));
//public NodeModelBase NodeModel;
/// <summary>
/// 所在的节点
@@ -52,6 +55,7 @@ namespace Serein.Workbench.Node.View
set { SetValue(JunctionTypeProperty, value.ToString()); }
}
#endregion
protected readonly StreamGeometry StreamGeometry = new StreamGeometry();
protected override Geometry DefiningGeometry => StreamGeometry;
@@ -65,15 +69,29 @@ namespace Serein.Workbench.Node.View
/// </summary>
public abstract Point MyCenterPoint { get; }
// 处理鼠标悬停状态
/// <summary>
/// 禁止连接
/// </summary>
private bool IsConnectionDisable;
/// <summary>
/// 处理鼠标悬停状态
/// </summary>
private bool _isMouseOver;
public bool IsMouseOver
{
get => _isMouseOver;
set
{
_isMouseOver = value;
InvalidateVisual();
if(_isMouseOver != value)
{
GlobalJunctionData.MyGlobalConnectingData.CurrentJunction = this;
_isMouseOver = value;
InvalidateVisual();
}
}
}
@@ -86,13 +104,63 @@ namespace Serein.Workbench.Node.View
Render(drawingContext);
}
protected void ControlPointBase_MouseMove(object sender, MouseEventArgs e)
/// <summary>
/// 获取背景颜色
/// </summary>
/// <returns></returns>
protected Brush GetBackgrounp()
{
if (GlobalJunctionData.MyGlobalConnectingData is null) return;
GlobalJunctionData.MyGlobalConnectingData.CurrentJunction = this;
var myData = GlobalJunctionData.MyGlobalConnectingData;
if(!myData.IsCreateing)
{
return Brushes.Transparent;
}
if (IsMouseOver)
{
if (myData.IsCanConnected)
{
if (myData.Type == JunctionOfConnectionType.Invoke)
{
return myData.ConnectionInvokeType.ToLineColor();
}
else
{
return myData.ConnectionArgSourceType.ToLineColor();
}
}
else
{
return Brushes.Red;
}
}
else
{
return Brushes.Transparent;
}
}
private object lockObj = new object();
// 控件获得鼠标焦点事件
private void JunctionControlBase_MouseMove(object sender, MouseEventArgs e)
{
//if (!GlobalJunctionData.MyGlobalConnectingData.IsCreateing) return;
//if (IsMouseOver) return;
IsMouseOver = true;
//this.InvalidateVisual();
}
// 控件失去鼠标焦点事件
private void JunctionControlBase_MouseLeave(object sender, MouseEventArgs e)
{
IsMouseOver = false;
e.Handled = true;
//Console.WriteLine("控件失去鼠标焦点");
}
/// <summary>
@@ -100,20 +168,43 @@ namespace Serein.Workbench.Node.View
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void ControlPointBase_MouseDown(object sender, MouseButtonEventArgs e)
protected void JunctionControlBase_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
GlobalJunctionData.MyGlobalConnectingData = new ConnectingData();
var myDataType = GlobalJunctionData.MyGlobalConnectingData;
myDataType.StartJunction = this;
var canvas = MainWindow.GetParentOfType<Canvas>(this);
if (canvas != null)
{
//myDataType.StartPoint = this.MyCenterPoint;
myDataType.StartPoint = this.TranslatePoint(new Point(this.Width / 2, this.Height / 2), canvas);
var bezierLine = new BezierLine(LineType.Bezier, myDataType.StartPoint, myDataType.StartPoint, Brushes.Green);
myDataType.VirtualLine = new MyLine(canvas, bezierLine);
var myData = GlobalJunctionData.MyGlobalConnectingData;
myData.Reset();
myData.IsCreateing = true; // 表示开始连接
myData.StartJunction = this;
myData.CurrentJunction = this;
myData.StartPoint = this.TranslatePoint(new Point(this.Width / 2, this.Height / 2), canvas);
var junctionOfConnectionType = this.JunctionType.ToConnectyionType();
ConnectionLineShape bezierLine; // 类别
Brush brushColor; // 临时线的颜色
if (junctionOfConnectionType == JunctionOfConnectionType.Invoke)
{
brushColor = ConnectionInvokeType.IsSucceed.ToLineColor();
}
else if(junctionOfConnectionType == JunctionOfConnectionType.Arg)
{
brushColor = ConnectionArgSourceType.GetOtherNodeData.ToLineColor();
}
else
{
return;
}
bezierLine = new ConnectionLineShape(LineType.Bezier,
myData.StartPoint,
myData.StartPoint,
brushColor,
isTop: true); // 绘制临时的线
Mouse.OverrideCursor = Cursors.Cross; // 设置鼠标为正在创建连线
myData.MyLine = new MyLine(canvas, bezierLine);
}
}
e.Handled = true;
@@ -123,6 +214,11 @@ namespace Serein.Workbench.Node.View
{
return new Point(this.ActualWidth / 2, this.ActualHeight / 2); // 起始节点选择右侧边缘中心
}
}

View File

@@ -1,7 +1,10 @@
using System;
using Serein.Library;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -13,28 +16,60 @@ namespace Serein.Workbench.Node.View
#region Model
public class MyLine
{
public MyLine(Canvas canvas, BezierLine line)
public MyLine(Canvas canvas, ConnectionLineShape line)
{
Canvas = canvas;
VirtualLine = line;
Line = line;
canvas?.Children.Add(line);
}
public Canvas Canvas { get; set; }
public BezierLine VirtualLine { get; set; }
public ConnectionLineShape Line { get; set; }
public void Remove()
{
Canvas?.Children.Remove(VirtualLine);
Canvas?.Children.Remove(Line);
}
}
public class ConnectingData
{
/// <summary>
/// 是否正在创建连线
/// </summary>
public bool IsCreateing { get; set; }
/// <summary>
/// 起始控制点
/// </summary>
public JunctionControlBase StartJunction { get; set; }
/// <summary>
/// 当前的控制点
/// </summary>
public JunctionControlBase CurrentJunction { get; set; }
/// <summary>
/// 开始坐标
/// </summary>
public Point StartPoint { get; set; }
public MyLine VirtualLine { get; set; }
/// <summary>
/// 线条样式
/// </summary>
public MyLine MyLine { get; set; }
/// <summary>
/// 线条类别(方法调用)
/// </summary>
public ConnectionInvokeType ConnectionInvokeType { get; set; } = ConnectionInvokeType.IsSucceed;
/// <summary>
/// 线条类别(参数传递)
/// </summary>
public ConnectionArgSourceType ConnectionArgSourceType { get; set; } = ConnectionArgSourceType.GetOtherNodeData;
/// <summary>
/// 判断当前连接类型
/// </summary>
public JunctionOfConnectionType Type => StartJunction.JunctionType.ToConnectyionType();
/// <summary>
/// 是否允许连接
@@ -42,32 +77,22 @@ namespace Serein.Workbench.Node.View
public bool IsCanConnected { get
{
if(StartJunction is null
|| CurrentJunction is null
)
{
return false;
}
if (!StartPoint.Equals(CurrentJunction))
if (!StartJunction.MyNode.Equals(CurrentJunction.MyNode)
&& StartJunction.JunctionType.IsCanConnection(CurrentJunction.JunctionType))
{
return true;
}
else
{
// 自己连接自己的情况下只能是从arg控制点连接到execute控制点。
if (CurrentJunction.JunctionType == Library.JunctionType.Execute
&& StartJunction.JunctionType == Library.JunctionType.ArgData)
{
return true;
}
if (CurrentJunction.JunctionType == Library.JunctionType.ArgData
&& StartJunction.JunctionType == Library.JunctionType.Execute)
{
// 需要是自己连接自己且只能是从arg控制点连接到execute控制点。
return true;
}
return false;
}
}
@@ -88,46 +113,48 @@ namespace Serein.Workbench.Node.View
if (StartJunction.JunctionType == Library.JunctionType.Execute
|| StartJunction.JunctionType == Library.JunctionType.ArgData)
{
VirtualLine.VirtualLine.UpdateStartPoints(point);
MyLine.Line.UpdateStartPoints(point);
}
else
{
VirtualLine.VirtualLine.UpdateEndPoints(point);
MyLine.Line.UpdateEndPoints(point);
}
}
/// <summary>
/// 重置
/// </summary>
public void Reset()
{
IsCreateing = false;
StartJunction = null;
CurrentJunction = null;
MyLine?.Remove();
ConnectionInvokeType = ConnectionInvokeType.IsSucceed;
ConnectionArgSourceType = ConnectionArgSourceType.GetOtherNodeData;
}
}
public static class GlobalJunctionData
{
private static ConnectingData? myGlobalData;
private static object _lockObj = new object();
//private static ConnectingData? myGlobalData;
//private static object _lockObj = new object();
/// <summary>
/// 创建节点之间控制点的连接行为
/// </summary>
public static ConnectingData? MyGlobalConnectingData
{
get => myGlobalData;
set
{
lock (_lockObj)
{
myGlobalData ??= value;
}
}
}
public static ConnectingData MyGlobalConnectingData { get; } = new ConnectingData();
/// <summary>
/// 删除连接视觉效果
/// </summary>
public static void OK()
{
myGlobalData?.VirtualLine.Remove();
myGlobalData = null;
MyGlobalConnectingData.Reset();
}
}
#endregion

View File

@@ -30,29 +30,27 @@ namespace Serein.Workbench.Node.View
#endregion
private Point _myCenterPoint;
public override Point MyCenterPoint { get => _myCenterPoint; }
public override void Render(DrawingContext drawingContext)
{
double width = ActualWidth;
double height = ActualHeight;
var background = GetBackgrounp();
// 输入连接器的背景
var connectorBackground = IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent;
var connectorRect = new Rect(4, 4, width - 8, height - 8);
drawingContext.DrawRectangle(connectorBackground, null, connectorRect);
var connectorRect = new Rect(0, 0, width, height);
drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect);
// 定义圆形的大小和位置
double connectorSize = 10; // 连接器的大小
double circleCenterX = 8; // 圆心 X 坐标
double circleCenterY = height / 2; // 圆心 Y 坐标
var circlePoint = new Point(circleCenterX, circleCenterY);
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标
// 绘制连接器的圆形部分
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY);
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), ellipse);
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), ellipse);
// 定义三角形的间距
double triangleOffsetX = 4; // 三角形与圆形的间距
@@ -68,7 +66,7 @@ namespace Serein.Workbench.Node.View
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
}
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), pathGeometry);
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), pathGeometry);
}
}

View File

@@ -23,7 +23,7 @@ namespace Serein.Workbench.Node.View
{
double width = ActualWidth;
double height = ActualHeight;
var background = GetBackgrounp();
// 绘制边框
//var borderBrush = new SolidColorBrush(Colors.Black);
//var borderThickness = 1.0;
@@ -31,22 +31,22 @@ namespace Serein.Workbench.Node.View
//drawingContext.DrawRectangle(null, new Pen(borderBrush, borderThickness), borderRect);
// 输入连接器的背景
var connectorBackground = IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent;
var connectorRect = new Rect(4, 4, width - 8, height - 8);
drawingContext.DrawRectangle(connectorBackground, null, connectorRect);
var connectorRect = new Rect(0, 0, width, height);
drawingContext.DrawRectangle(Brushes.Transparent,null, connectorRect);
//drawingContext.DrawRectangle(Brushes.Transparent, new Pen(background,2), connectorRect);
// 定义圆形的大小和位置
double connectorSize = 10; // 连接器的大小
double circleCenterX = 8; // 圆心 X 坐标
double circleCenterY = height / 2; // 圆心 Y 坐标
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标
var circlePoint = new Point(circleCenterX, circleCenterY);
// 绘制连接器的圆形部分
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY);
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), ellipse);
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), ellipse);
@@ -65,7 +65,7 @@ namespace Serein.Workbench.Node.View
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
}
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), pathGeometry);
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), pathGeometry);
// 绘制标签
//var formattedText = new FormattedText(

View File

@@ -20,26 +20,25 @@ namespace Serein.Workbench.Node.View
{
double width = ActualWidth;
double height = ActualHeight;
var background = GetBackgrounp();
// 输入连接器的背景
var connectorBackground = IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent;
var connectorRect = new Rect(4, 4, width - 8, height - 8);
drawingContext.DrawRectangle(connectorBackground, null, connectorRect);
var connectorRect = new Rect(0, 0, width, height);
drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect);
// 定义圆形的大小和位置
double connectorSize = 10; // 连接器的大小
double circleCenterX = 8; // 圆心 X 坐标
double circleCenterY = height / 2; // 圆心 Y 坐标
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标
var circlePoint = new Point(circleCenterX, circleCenterY);
// 绘制连接器的圆形部分
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), ellipse);
_myCenterPoint = new Point(circleCenterX + connectorSize / 2, circleCenterY);
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), ellipse);
// 绘制连接器的圆形部分
//var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
// 定义三角形的间距
double triangleOffsetX = 4; // 三角形与圆形的间距
@@ -55,7 +54,7 @@ namespace Serein.Workbench.Node.View
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
}
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), pathGeometry);
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), pathGeometry);
}
}
}

View File

@@ -24,9 +24,10 @@ namespace Serein.Workbench.Node.View
double height = ActualHeight;
// 输入连接器的背景
var connectorBackground = IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent;
var connectorRect = new Rect(4, 4, width - 8, height - 8);
drawingContext.DrawRectangle(connectorBackground, null, connectorRect);
var connectorRect = new Rect(0, 0, width, height);
drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect);
var background = GetBackgrounp();
// 定义圆形的大小和位置
double connectorSize = 10; // 连接器的大小
@@ -34,10 +35,11 @@ namespace Serein.Workbench.Node.View
double circleCenterY = height / 2; // 圆心 Y 坐标
var circlePoint = new Point(circleCenterX, circleCenterY);
_myCenterPoint = new Point(circleCenterX - connectorSize / 2 , circleCenterY); // 中心坐标
// 绘制连接器的圆形部分
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY);
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), ellipse);
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), ellipse);
// 定义三角形的间距
double triangleOffsetX = 4; // 三角形与圆形的间距
@@ -53,7 +55,7 @@ namespace Serein.Workbench.Node.View
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
}
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), pathGeometry);
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), pathGeometry);
}
}
}