Files
serein-flow/Workbench/Node/Junction/JunctionControlBase.cs

411 lines
13 KiB
C#
Raw Normal View History

2025-01-05 08:52:37 +08:00
using Serein.Library;
using Serein.Library.Utils;
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;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;
using System.Windows.Documents;
using System.Threading;
using Serein.Workbench.Services;
using Serein.Workbench.Tool;
using System.ComponentModel;
using System.Diagnostics;
2025-01-05 08:52:37 +08:00
namespace Serein.Workbench.Node.View
{
/// <summary>
/// 控制带的拓展方法
/// </summary>
2025-01-05 08:52:37 +08:00
internal static class MyUIFunc
{
public static Pen CreateAndFreezePen()
{
// 创建Pen
Pen pen = new Pen(Brushes.Black, 1);
// 冻结Pen
if (pen.CanFreeze)
{
pen.Freeze();
}
return pen;
}
}
/// <summary>
/// 入参控件
/// </summary>
2025-01-05 08:52:37 +08:00
public class ParamsArgControl: Shape
{
public ParamsArgControl()
{
this.MouseDown += ParamsArg_OnMouseDown; // 增加或删除
this.MouseMove += ParamsArgControl_MouseMove;
this.MouseLeave += ParamsArgControl_MouseLeave;
AddOrRemoveParamsTask = AddParamAsync;
2025-01-05 08:52:37 +08:00
}
protected readonly StreamGeometry StreamGeometry = new StreamGeometry();
protected override Geometry DefiningGeometry => StreamGeometry;
#region
public static readonly DependencyProperty NodeProperty =
DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(ParamsArgControl), new PropertyMetadata(default(NodeModelBase)));
//public NodeModelBase NodeModel;
/// <summary>
/// 所在的节点
/// </summary>
public NodeModelBase MyNode
{
get { return (NodeModelBase)GetValue(NodeProperty); }
set { SetValue(NodeProperty, value); }
}
#endregion
#region
public static readonly DependencyProperty ArgIndexProperty =
DependencyProperty.Register(nameof(ArgIndex), typeof(int), typeof(ParamsArgControl), new PropertyMetadata(default(int)));
/// <summary>
/// 参数的索引
/// </summary>
public int ArgIndex
{
get { return (int)GetValue(ArgIndexProperty); }
set { SetValue(ArgIndexProperty, value.ToString()); }
}
#endregion
/// <summary>
/// 控件重绘事件
/// </summary>
/// <param name="drawingContext"></param>
protected override void OnRender(DrawingContext drawingContext)
{
Brush brush = isMouseOver ? Brushes.Red : Brushes.Green;
double height = ActualHeight;
// 定义圆形的大小和位置
double connectorSize = 10; // 连接器的大小
double circleCenterX = 8; // 圆心 X 坐标
double circleCenterY = height / 2; // 圆心 Y 坐标
var circlePoint = new Point(circleCenterX, circleCenterY);
// 圆形部分
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
drawingContext.DrawGeometry(brush, MyUIFunc.CreateAndFreezePen(), ellipse);
}
private bool isMouseOver; // 鼠标悬停状态
private Func<Task> AddOrRemoveParamsTask; // 增加或删除参数
public async void ParamsArg_OnMouseDown(object sender, MouseButtonEventArgs e)
{
await AddOrRemoveParamsTask.Invoke();
}
private void ParamsArgControl_MouseMove(object sender, MouseEventArgs e)
{
isMouseOver = true;
if (cts.IsCancellationRequested) {
cts = new CancellationTokenSource();
2025-01-05 08:52:37 +08:00
Task.Run(async () =>
{
await Task.Delay(380);
}, cts.Token).ContinueWith((t) =>
2025-01-05 08:52:37 +08:00
{
// 如果焦点仍在控件上时,则改变点击事件
if (isMouseOver)
{
AddOrRemoveParamsTask = RemoveParamAsync;
2025-01-05 08:52:37 +08:00
this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘
}
});
}
}
private CancellationTokenSource cts = new CancellationTokenSource();
2025-01-05 08:52:37 +08:00
private void ParamsArgControl_MouseLeave(object sender, MouseEventArgs e)
{
isMouseOver = false;
AddOrRemoveParamsTask = AddParamAsync; // 鼠标焦点离开时恢复点击事件
cts?.Cancel();
2025-01-05 08:52:37 +08:00
this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘
}
private async Task AddParamAsync()
2025-01-05 08:52:37 +08:00
{
await this.MyNode.Env.ChangeParameter(MyNode.Guid, true, ArgIndex);
}
private async Task RemoveParamAsync()
2025-01-05 08:52:37 +08:00
{
await this.MyNode.Env.ChangeParameter(MyNode.Guid, false, ArgIndex);
}
}
public abstract class JunctionControlBase : Shape
{
private readonly FlowNodeService flowNodeService;
2025-01-05 08:52:37 +08:00
protected JunctionControlBase()
{
2025-01-05 08:52:37 +08:00
this.Width = 25;
this.Height = 20;
this.MouseDown += JunctionControlBase_MouseDown;
this.MouseMove += JunctionControlBase_MouseMove;
this.MouseLeave += JunctionControlBase_MouseLeave;
#if DEBUG
if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
return;
#endif
flowNodeService = App.GetService<FlowNodeService>();
2025-01-05 08:52:37 +08:00
}
2025-01-05 08:52:37 +08:00
#region
public static readonly DependencyProperty NodeProperty =
DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(JunctionControlBase), new PropertyMetadata(default(NodeModelBase)));
//public NodeModelBase NodeModel;
/// <summary>
/// 所在的节点
/// </summary>
public NodeModelBase MyNode
{
get { return (NodeModelBase)GetValue(NodeProperty); }
set { SetValue(NodeProperty, value); }
}
#endregion
#region
public static readonly DependencyProperty JunctionTypeProperty =
DependencyProperty.Register(nameof(JunctionType), typeof(string), typeof(JunctionControlBase), new PropertyMetadata(default(string)));
/// <summary>
/// 控制点类型
/// </summary>
public JunctionType JunctionType
{
get { return EnumHelper.ConvertEnum<JunctionType>(GetValue(JunctionTypeProperty).ToString()); }
set { SetValue(JunctionTypeProperty, value.ToString()); }
}
#endregion
protected readonly StreamGeometry StreamGeometry = new StreamGeometry();
protected override Geometry DefiningGeometry => StreamGeometry;
/// <summary>
/// 重绘方法
/// </summary>
/// <param name="drawingContext"></param>
public abstract void Render(DrawingContext drawingContext);
/// <summary>
/// 中心点
/// </summary>
public abstract Point MyCenterPoint { get; }
/// <summary>
/// 禁止连接
/// </summary>
private bool IsConnectionDisable;
/// <summary>
/// 处理鼠标悬停状态
/// </summary>
private bool _isMouseOver;
public bool IsMouseOver
{
get => _isMouseOver;
set
{
if(_isMouseOver != value)
{
if(flowNodeService is not null)
{
flowNodeService.ConnectingData.CurrentJunction = this;
}
2025-01-05 08:52:37 +08:00
_isMouseOver = value;
InvalidateVisual();
}
}
}
/// <summary>
/// 控件重绘事件
/// </summary>
/// <param name="drawingContext"></param>
protected override void OnRender(DrawingContext drawingContext)
{
Render(drawingContext);
}
/// <summary>
/// 获取背景颜色
/// </summary>
/// <returns></returns>
protected Brush GetBackgrounp()
{
if(flowNodeService is null)
{
return Brushes.Transparent;
}
var cd = flowNodeService.ConnectingData;
if(!cd.IsCreateing)
2025-01-05 08:52:37 +08:00
{
return Brushes.Transparent;
}
if (IsMouseOver)
{
if (cd.IsCanConnected)
2025-01-05 08:52:37 +08:00
{
if (cd.Type == JunctionOfConnectionType.Invoke)
2025-01-05 08:52:37 +08:00
{
return cd.ConnectionInvokeType.ToLineColor();
2025-01-05 08:52:37 +08:00
}
else
{
return cd.ConnectionArgSourceType.ToLineColor();
2025-01-05 08:52:37 +08:00
}
}
else
{
return Brushes.Red;
}
}
else
{
return Brushes.Transparent;
}
}
private object lockObj = new object();
/// <summary>
/// 控件获得鼠标焦点事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void JunctionControlBase_MouseMove(object sender, MouseEventArgs e)
{
//if (!GlobalJunctionData.MyGlobalConnectingData.IsCreateing) return;
//if (IsMouseOver) return;
IsMouseOver = true;
//this.InvalidateVisual();
}
/// <summary>
/// 控件失去鼠标焦点事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void JunctionControlBase_MouseLeave(object sender, MouseEventArgs e)
{
IsMouseOver = false;
e.Handled = true;
}
/// <summary>
/// 在碰撞点上按下鼠标控件开始进行移动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void JunctionControlBase_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
var canvas = WpfFuncTool.GetParentOfType<Canvas>(this);
2025-01-05 08:52:37 +08:00
if (canvas != null)
{
var cd = flowNodeService.ConnectingData;
cd.Reset();
cd.IsCreateing = true; // 表示开始连接
cd.StartJunction = this;
cd.CurrentJunction = this;
cd.StartPoint = this.TranslatePoint(new Point(this.Width / 2, this.Height / 2), canvas);
2025-01-05 08:52:37 +08:00
var junctionOfConnectionType = this.JunctionType.ToConnectyionType();
//Debug.WriteLine(this.JunctionType);
2025-01-05 08:52:37 +08:00
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,
cd.StartPoint,
cd.StartPoint,
2025-01-05 08:52:37 +08:00
brushColor,
isTop: true); // 绘制临时的线
Mouse.OverrideCursor = Cursors.Cross; // 设置鼠标为正在创建连线
cd.MyLine = new MyLine(canvas, bezierLine);
2025-01-05 08:52:37 +08:00
}
}
e.Handled = true;
}
private Point GetStartPoint()
{
return new Point(this.ActualWidth / 2, this.ActualHeight / 2); // 起始节点选择右侧边缘中心
}
}
}