修复HUB节点断开链接BUG 将编辑器连线图层移动至节点图层后方 修改部分STNode重载ADD:(OnSetOptionDotLocation,OnSetOptionTextRectangle,OnEditorLoadCompleted) 对保存的文件进行GZIP压缩

This commit is contained in:
DebugST 2021-01-21 18:18:42 +08:00
parent f429f2d0a9
commit 5323358eb0
15 changed files with 507 additions and 130 deletions

View File

@ -23,13 +23,14 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\ST.Library.UI.XML</DocumentationFile> <DocumentationFile>bin\Release\ST.Library.UI.XML</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />

View File

@ -48,10 +48,11 @@ namespace ST.Library.UI
internal set { internal set {
if (value == _Owner) return; if (value == _Owner) return;
if (_Owner != null) { if (_Owner != null) {
foreach (STNodeOption op in this._InputOptions) op.DisConnectionAll(); foreach (STNodeOption op in this._InputOptions.ToArray()) op.DisConnectionAll();
foreach (STNodeOption op in this._OutputOptions) op.DisConnectionAll(); foreach (STNodeOption op in this._OutputOptions.ToArray()) op.DisConnectionAll();
} }
_Owner = value; _Owner = value;
this.BuildSize(true, true, false);
this.OnOwnerChanged(); this.OnOwnerChanged();
} }
} }
@ -368,8 +369,14 @@ namespace ST.Library.UI
set { _Tag = value; } set { _Tag = value; }
} }
private bool m_isBuildNodeSize; private Guid _Guid;
private bool m_isBuildMarkSize; /// <summary>
/// 获取全局唯一标识
/// </summary>
public Guid Guid {
get { return _Guid; }
}
private static Point m_static_pt_init = new Point(10, 10); private static Point m_static_pt_init = new Point(10, 10);
public STNode(/*string strTitle, int x, int y*/) { public STNode(/*string strTitle, int x, int y*/) {
@ -395,6 +402,7 @@ namespace ST.Library.UI
m_sf.SetTabStops(0, new float[] { 40 }); m_sf.SetTabStops(0, new float[] { 40 });
m_static_pt_init.X += 10; m_static_pt_init.X += 10;
m_static_pt_init.Y += 10; m_static_pt_init.Y += 10;
this._Guid = Guid.NewGuid();
this.OnCreate(); this.OnCreate();
} }
@ -409,30 +417,34 @@ namespace ST.Library.UI
/// </summary> /// </summary>
protected STNodeControl m_ctrl_hover; protected STNodeControl m_ctrl_hover;
public void BuildSize(bool bBuildNode, bool bBuildMark, bool bRedraw) { protected internal void BuildSize(bool bBuildNode, bool bBuildMark, bool bRedraw) {
m_isBuildNodeSize = bBuildNode; if (this._Owner == null) return;
m_isBuildMarkSize = bBuildMark; Pen p = new Pen(this._BackColor);
if (bRedraw) { SolidBrush sb = new SolidBrush(this._BackColor);
if (this._Owner != null) this._Owner.Invalidate(); using (Graphics g = this._Owner.CreateGraphics()) {
} DrawingTools dt = new DrawingTools() {
} Graphics = g,
Pen = p,
internal void CheckSize(DrawingTools dt) { SolidBrush = sb
if (m_isBuildNodeSize) { };
if (bBuildNode) {
Size sz = this.OnBuildNodeSize(dt); Size sz = this.OnBuildNodeSize(dt);
this._Width = sz.Width; this._Width = sz.Width;
this._Height = sz.Height; this._Height = sz.Height;
m_isBuildNodeSize = false; this.SetOptionLocation();
this.OnResize(new EventArgs());
} }
if (m_isBuildMarkSize) { if (bBuildMark) {
m_isBuildMarkSize = true;
if (string.IsNullOrEmpty(this._Mark)) return; if (string.IsNullOrEmpty(this._Mark)) return;
this._MarkRectangle = this.OnBuildMarkRectangle(dt); this._MarkRectangle = this.OnBuildMarkRectangle(dt);
} }
} }
if (bRedraw) this._Owner.Invalidate();
}
internal Dictionary<string, byte[]> OnSaveNode() { internal Dictionary<string, byte[]> OnSaveNode() {
Dictionary<string, byte[]> dic = new Dictionary<string, byte[]>(); Dictionary<string, byte[]> dic = new Dictionary<string, byte[]>();
dic.Add("Guid", this._Guid.ToByteArray());
dic.Add("Left", BitConverter.GetBytes(this._Left)); dic.Add("Left", BitConverter.GetBytes(this._Left));
dic.Add("Top", BitConverter.GetBytes(this._Top)); dic.Add("Top", BitConverter.GetBytes(this._Top));
dic.Add("Mark", string.IsNullOrEmpty(this._Mark) ? new byte[] { 0 } : Encoding.UTF8.GetBytes(this._Mark)); dic.Add("Mark", string.IsNullOrEmpty(this._Mark) ? new byte[] { 0 } : Encoding.UTF8.GetBytes(this._Mark));
@ -444,7 +456,11 @@ namespace ST.Library.UI
internal virtual byte[] GetSaveData() { internal virtual byte[] GetSaveData() {
List<byte> lst = new List<byte>(); List<byte> lst = new List<byte>();
byte[] byData = Encoding.UTF8.GetBytes(this.GetType().GUID.ToString()); Type t = this.GetType();
byte[] byData = Encoding.UTF8.GetBytes(t.Module.Name);
lst.Add((byte)byData.Length);
lst.AddRange(byData);
byData = Encoding.UTF8.GetBytes(t.GUID.ToString());
lst.Add((byte)byData.Length); lst.Add((byte)byData.Length);
lst.AddRange(byData); lst.AddRange(byData);
@ -552,31 +568,13 @@ namespace ST.Library.UI
/// <param name="dt">绘制工具</param> /// <param name="dt">绘制工具</param>
protected virtual void OnDrawBody(DrawingTools dt) { protected virtual void OnDrawBody(DrawingTools dt) {
SolidBrush brush = dt.SolidBrush; SolidBrush brush = dt.SolidBrush;
Rectangle rect = new Rectangle(this.Left + 10, this._Top + this._TitleHeight, this._Width - 20, m_nItemHeight);
m_sf.Alignment = StringAlignment.Near;
foreach (STNodeOption op in this._InputOptions) { foreach (STNodeOption op in this._InputOptions) {
brush.Color = op.TextColor;// this._ForeColor;
dt.Graphics.DrawString(op.Text, this._Font, brush, rect, m_sf);
op.DotLeft = this.Left - 5;
op.DotTop = rect.Y + 5;
Point pt = this.OnSetOptionLocation(op);
op.DotLeft = pt.X;
op.DotTop = pt.Y;
this.OnDrawOptionDot(dt, op); this.OnDrawOptionDot(dt, op);
rect.Y += m_nItemHeight; this.OnDrawOptionText(dt, op);
} }
rect.Y = this._Top + this._TitleHeight;
m_sf.Alignment = StringAlignment.Far;
foreach (STNodeOption op in this._OutputOptions) { foreach (STNodeOption op in this._OutputOptions) {
brush.Color = op.TextColor;// this._ForeColor;
dt.Graphics.DrawString(op.Text, this._Font, brush, rect, m_sf);
op.DotLeft = this.Left + this.Width - 5;
op.DotTop = rect.Y + 5;
Point pt = this.OnSetOptionLocation(op);
op.DotLeft = pt.X;
op.DotTop = pt.Y;
this.OnDrawOptionDot(dt, op); this.OnDrawOptionDot(dt, op);
rect.Y += m_nItemHeight; this.OnDrawOptionText(dt, op);
} }
if (this._Controls.Count != 0) { //绘制子控件 if (this._Controls.Count != 0) { //绘制子控件
//将坐标原点与节点对齐 //将坐标原点与节点对齐
@ -655,12 +653,38 @@ namespace ST.Library.UI
} }
} }
/// <summary> /// <summary>
/// 当计算Option位置时候发生 /// 绘制选项的文本
/// </summary>
/// <param name="dt">绘制工具</param>
/// <param name="op">指定的选项</param>
protected virtual void OnDrawOptionText(DrawingTools dt, STNodeOption op) {
Graphics g = dt.Graphics;
SolidBrush brush = dt.SolidBrush;
if (op.IsInput) {
m_sf.Alignment = StringAlignment.Near;
} else {
m_sf.Alignment = StringAlignment.Far;
}
brush.Color = op.TextColor;
g.DrawString(op.Text, this.Font, brush, op.TextRectangle, m_sf);
}
/// <summary>
/// 当计算Option连线点位置时候发生
/// </summary> /// </summary>
/// <param name="op">需要计算的Option</param> /// <param name="op">需要计算的Option</param>
/// <param name="pt">自动计算出的位置</param>
/// <returns>新的位置</returns> /// <returns>新的位置</returns>
protected virtual Point OnSetOptionLocation(STNodeOption op) { protected virtual Point OnSetOptionDotLocation(STNodeOption op, Point pt) {
return new Point(op.DotLeft, op.DotTop); return pt;
}
/// <summary>
/// 当计算Option文本区域时候发生
/// </summary>
/// <param name="op">需要计算的Option</param>
/// <param name="rect">自动计算出的区域</param>
/// <returns>新的区域</returns>
protected virtual Rectangle OnSetOptionTextRectangle(STNodeOption op, Rectangle rect) {
return rect;
} }
/// <summary> /// <summary>
/// 计算当前Node所需要的矩形区域 /// 计算当前Node所需要的矩形区域
@ -712,6 +736,7 @@ namespace ST.Library.UI
/// </summary> /// </summary>
/// <param name="dic">保存时候的数据</param> /// <param name="dic">保存时候的数据</param>
protected internal virtual void OnLoadNode(Dictionary<string, byte[]> dic) { protected internal virtual void OnLoadNode(Dictionary<string, byte[]> dic) {
if (dic.ContainsKey("Guid")) this._Guid = new Guid(dic["Guid"]);
if (dic.ContainsKey("Left")) this._Left = BitConverter.ToInt32(dic["Left"], 0); if (dic.ContainsKey("Left")) this._Left = BitConverter.ToInt32(dic["Left"], 0);
if (dic.ContainsKey("Top")) this._Top = BitConverter.ToInt32(dic["Top"], 0); if (dic.ContainsKey("Top")) this._Top = BitConverter.ToInt32(dic["Top"], 0);
if (dic.ContainsKey("Mark")) { if (dic.ContainsKey("Mark")) {
@ -721,6 +746,12 @@ namespace ST.Library.UI
if (dic.ContainsKey("LockOption")) this._LockOption = dic["LockOption"][0] == 1; if (dic.ContainsKey("LockOption")) this._LockOption = dic["LockOption"][0] == 1;
if (dic.ContainsKey("LockLocation")) this._LockLocation = dic["LockLocation"][0] == 1; if (dic.ContainsKey("LockLocation")) this._LockLocation = dic["LockLocation"][0] == 1;
} }
/// <summary>
/// 当编辑器加载完成所有的节点时候发生
/// </summary>
protected internal virtual void OnEditorLoadCompleted() {
}
//[event]===========================[event]==============================[event]============================[event] //[event]===========================[event]==============================[event]============================[event]
@ -821,8 +852,8 @@ namespace ST.Library.UI
if (m_ctrl_active != null) m_ctrl_active.OnKeyPress(e); if (m_ctrl_active != null) m_ctrl_active.OnKeyPress(e);
} }
protected internal virtual void OnMove(EventArgs e) { } protected internal virtual void OnMove(EventArgs e) { this.SetOptionLocation(); }
protected internal virtual void OnResize(EventArgs e) { } protected internal virtual void OnResize(EventArgs e) { this.SetOptionLocation(); }
/// <summary> /// <summary>
@ -840,6 +871,26 @@ namespace ST.Library.UI
#endregion protected #endregion protected
private void SetOptionLocation() {
Rectangle rect = new Rectangle(this.Left + 10, this._Top + this._TitleHeight, this._Width - 20, m_nItemHeight);
foreach (STNodeOption op in this._InputOptions) {
Point pt = this.OnSetOptionDotLocation(op, new Point(this.Left - 5, rect.Y + 5));
op.TextRectangle = this.OnSetOptionTextRectangle(op, rect);
op.DotLeft = pt.X;
op.DotTop = pt.Y;
rect.Y += m_nItemHeight;
}
rect.Y = this._Top + this._TitleHeight;
m_sf.Alignment = StringAlignment.Far;
foreach (STNodeOption op in this._OutputOptions) {
Point pt = this.OnSetOptionDotLocation(op, new Point(this._Left + this._Width - 5, rect.Y + 5));
op.TextRectangle = this.OnSetOptionTextRectangle(op, rect);
op.DotLeft = pt.X;
op.DotTop = pt.Y;
rect.Y += m_nItemHeight;
}
}
/// <summary> /// <summary>
/// 重绘Node /// 重绘Node
/// </summary> /// </summary>

View File

@ -27,7 +27,7 @@ namespace ST.Library.UI
if (-1 == nIndex) { if (-1 == nIndex) {
nIndex = this._Count; nIndex = this._Count;
node.Owner = m_owner; node.Owner = m_owner;
node.BuildSize(true, true, false); //node.BuildSize(true, true, false);
m_nodes[this._Count++] = node; m_nodes[this._Count++] = node;
m_owner.BuildBounds(); m_owner.BuildBounds();
m_owner.OnNodeAdded(new STNodeEditorEventArgs(node)); m_owner.OnNodeAdded(new STNodeEditorEventArgs(node));
@ -87,7 +87,7 @@ namespace ST.Library.UI
node.Owner = m_owner; node.Owner = m_owner;
m_nodes[nIndex] = node; m_nodes[nIndex] = node;
this._Count++; this._Count++;
node.BuildSize(true, true,false); //node.BuildSize(true, true,false);
m_owner.Invalidate(); m_owner.Invalidate();
m_owner.BuildBounds(); m_owner.BuildBounds();
} }
@ -225,5 +225,12 @@ namespace ST.Library.UI
IEnumerator IEnumerable.GetEnumerator() { IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator(); return this.GetEnumerator();
} }
public STNode[] ToArray() {
STNode[] nodes = new STNode[this._Count];
for (int i = 0; i < nodes.Length; i++)
nodes[i] = m_nodes[i];
return nodes;
}
} }
} }

View File

@ -10,6 +10,7 @@ using System.Drawing.Drawing2D;
using System.Threading; using System.Threading;
using System.ComponentModel; using System.ComponentModel;
using System.Reflection; using System.Reflection;
using System.IO.Compression;
/* /*
MIT License MIT License
@ -632,11 +633,12 @@ namespace ST.Library.UI
g.TranslateTransform(this._CanvasOffsetX, this._CanvasOffsetY); //移动坐标系 g.TranslateTransform(this._CanvasOffsetX, this._CanvasOffsetY); //移动坐标系
g.ScaleTransform(this._CanvasScale, this._CanvasScale); //缩放绘图表面 g.ScaleTransform(this._CanvasScale, this._CanvasScale); //缩放绘图表面
this.OnDrawNode(m_drawing_tools, this.ControlToCanvas(this.ClientRectangle));
this.OnDrawConnectedLine(m_drawing_tools); this.OnDrawConnectedLine(m_drawing_tools);
this.OnDrawNode(m_drawing_tools, this.ControlToCanvas(this.ClientRectangle));
if (m_ca == CanvasAction.ConnectOption) { //如果正在连线 if (m_ca == CanvasAction.ConnectOption) { //如果正在连线
m_drawing_tools.Pen.Color = this._HighLineColor; m_drawing_tools.Pen.Color = this._HighLineColor;
g.SmoothingMode = SmoothingMode.HighQuality;
if (m_option_down.IsInput) if (m_option_down.IsInput)
this.DrawBezier(g, m_drawing_tools.Pen, m_pt_in_canvas, m_pt_dot_down, this._Curvature); this.DrawBezier(g, m_drawing_tools.Pen, m_pt_in_canvas, m_pt_dot_down, this._Curvature);
else else
@ -777,11 +779,12 @@ namespace ST.Library.UI
this.OnHoverChanged(new EventArgs()); this.OnHoverChanged(new EventArgs());
bRedraw = true; bRedraw = true;
} }
if (this._HoverNode != null) if (this._HoverNode != null) {
this._HoverNode.OnMouseMove(new MouseEventArgs(e.Button, e.Clicks, this._HoverNode.OnMouseMove(new MouseEventArgs(e.Button, e.Clicks,
(int)m_pt_in_canvas.X - this._HoverNode.Left, (int)m_pt_in_canvas.X - this._HoverNode.Left,
(int)m_pt_in_canvas.Y - this._HoverNode.Top, e.Delta)); (int)m_pt_in_canvas.Y - this._HoverNode.Top, e.Delta));
m_gp_hover = null;
} else {
GraphicsPath gp = null; GraphicsPath gp = null;
foreach (var v in m_dic_gp_info) { //判断鼠标是否悬停到连线路径上 foreach (var v in m_dic_gp_info) { //判断鼠标是否悬停到连线路径上
if (v.Key.IsOutlineVisible(m_pt_in_canvas, m_p_line_hover)) { if (v.Key.IsOutlineVisible(m_pt_in_canvas, m_p_line_hover)) {
@ -793,6 +796,7 @@ namespace ST.Library.UI
m_gp_hover = gp; m_gp_hover = gp;
bRedraw = true; bRedraw = true;
} }
}
if (bRedraw) this.Invalidate(); if (bRedraw) this.Invalidate();
} }
@ -942,7 +946,7 @@ namespace ST.Library.UI
//var rect_canvas_display = this.ControlToCanvas(rect); //var rect_canvas_display = this.ControlToCanvas(rect);
Image img_border = null; Image img_border = null;
foreach (STNode n in this._Nodes) { foreach (STNode n in this._Nodes) {
n.CheckSize(dt); //n.CheckSize(dt);
img_border = m_img_border; img_border = m_img_border;
if (this._ShowBorder) { //如果绘制边框 判断状态 if (this._ShowBorder) { //如果绘制边框 判断状态
if (this._ActiveNode == n) img_border = m_img_border_active; if (this._ActiveNode == n) img_border = m_img_border_active;
@ -1701,24 +1705,26 @@ namespace ST.Library.UI
Dictionary<STNodeOption, long> dic = new Dictionary<STNodeOption, long>(); Dictionary<STNodeOption, long> dic = new Dictionary<STNodeOption, long>();
s.Write(new byte[] { (byte)'S', (byte)'T', (byte)'N', (byte)'D' }, 0, 4); //file head s.Write(new byte[] { (byte)'S', (byte)'T', (byte)'N', (byte)'D' }, 0, 4); //file head
s.WriteByte(1); //ver s.WriteByte(1); //ver
s.Write(BitConverter.GetBytes(this._CanvasOffsetX), 0, 4); using (GZipStream gs = new GZipStream(s, CompressionMode.Compress)) {
s.Write(BitConverter.GetBytes(this._CanvasOffsetY), 0, 4); gs.Write(BitConverter.GetBytes(this._CanvasOffsetX), 0, 4);
s.Write(BitConverter.GetBytes(this._CanvasScale), 0, 4); gs.Write(BitConverter.GetBytes(this._CanvasOffsetY), 0, 4);
s.Write(BitConverter.GetBytes(this._Nodes.Count), 0, 4); gs.Write(BitConverter.GetBytes(this._CanvasScale), 0, 4);
gs.Write(BitConverter.GetBytes(this._Nodes.Count), 0, 4);
foreach (STNode node in this._Nodes) { foreach (STNode node in this._Nodes) {
try { try {
byte[] byNode = node.GetSaveData(); byte[] byNode = node.GetSaveData();
s.Write(BitConverter.GetBytes(byNode.Length), 0, 4); gs.Write(BitConverter.GetBytes(byNode.Length), 0, 4);
s.Write(byNode, 0, byNode.Length); gs.Write(byNode, 0, byNode.Length);
foreach (STNodeOption op in node.InputOptions) dic.Add(op, dic.Count); foreach (STNodeOption op in node.InputOptions) dic.Add(op, dic.Count);
foreach (STNodeOption op in node.OutputOptions) dic.Add(op, dic.Count); foreach (STNodeOption op in node.OutputOptions) dic.Add(op, dic.Count);
} catch (Exception ex) { } catch (Exception ex) {
throw new Exception("获取节点数据出错-" + node.Title, ex); throw new Exception("获取节点数据出错-" + node.Title, ex);
} }
} }
s.Write(BitConverter.GetBytes(m_dic_gp_info.Count), 0, 4); gs.Write(BitConverter.GetBytes(m_dic_gp_info.Count), 0, 4);
foreach (var v in m_dic_gp_info.Values) foreach (var v in m_dic_gp_info.Values)
s.Write(BitConverter.GetBytes(((dic[v.Output] << 32) | dic[v.Input])), 0, 8); gs.Write(BitConverter.GetBytes(((dic[v.Output] << 32) | dic[v.Input])), 0, 8);
}
} }
/// <summary> /// <summary>
/// 获取画布中内容二进制数据 /// 获取画布中内容二进制数据
@ -1800,31 +1806,37 @@ namespace ST.Library.UI
if (BitConverter.ToInt32(byLen, 0) != BitConverter.ToInt32(new byte[] { (byte)'S', (byte)'T', (byte)'N', (byte)'D' }, 0)) if (BitConverter.ToInt32(byLen, 0) != BitConverter.ToInt32(new byte[] { (byte)'S', (byte)'T', (byte)'N', (byte)'D' }, 0))
throw new InvalidDataException("无法识别的文件类型"); throw new InvalidDataException("无法识别的文件类型");
if (s.ReadByte() != 1) throw new InvalidDataException("无法识别的文件版本号"); if (s.ReadByte() != 1) throw new InvalidDataException("无法识别的文件版本号");
s.Read(byLen, 0, 4); using (GZipStream gs = new GZipStream(s, CompressionMode.Decompress)) {
gs.Read(byLen, 0, 4);
float x = BitConverter.ToSingle(byLen, 0); float x = BitConverter.ToSingle(byLen, 0);
s.Read(byLen, 0, 4); gs.Read(byLen, 0, 4);
float y = BitConverter.ToSingle(byLen, 0); float y = BitConverter.ToSingle(byLen, 0);
s.Read(byLen, 0, 4); gs.Read(byLen, 0, 4);
float scale = BitConverter.ToSingle(byLen, 0); float scale = BitConverter.ToSingle(byLen, 0);
s.Read(byLen, 0, 4); gs.Read(byLen, 0, 4);
int nCount = BitConverter.ToInt32(byLen, 0); int nCount = BitConverter.ToInt32(byLen, 0);
Dictionary<long, STNodeOption> dic = new Dictionary<long, STNodeOption>(); Dictionary<long, STNodeOption> dic = new Dictionary<long, STNodeOption>();
byte[] byData = null; byte[] byData = null;
for (int i = 0; i < nCount; i++) { for (int i = 0; i < nCount; i++) {
s.Read(byLen, 0, byLen.Length); gs.Read(byLen, 0, byLen.Length);
nLen = BitConverter.ToInt32(byLen, 0); nLen = BitConverter.ToInt32(byLen, 0);
byData = new byte[nLen]; byData = new byte[nLen];
s.Read(byData, 0, byData.Length); gs.Read(byData, 0, byData.Length);
STNode node = this.GetNodeFromData(byData); STNode node = null;
try { this._Nodes.Add(node); } catch (Exception ex) { throw new Exception("加载节点出错-" + node.Title, ex); } try { node = this.GetNodeFromData(byData); } catch (Exception ex) {
throw new Exception("加载节点时发生错误可能数据已损坏\r\n" + ex.Message, ex);
}
try { this._Nodes.Add(node); } catch (Exception ex) {
throw new Exception("加载节点出错-" + node.Title, ex);
}
foreach (STNodeOption op in node.InputOptions) dic.Add(dic.Count, op); foreach (STNodeOption op in node.InputOptions) dic.Add(dic.Count, op);
foreach (STNodeOption op in node.OutputOptions) dic.Add(dic.Count, op); foreach (STNodeOption op in node.OutputOptions) dic.Add(dic.Count, op);
} }
s.Read(byLen, 0, 4); gs.Read(byLen, 0, 4);
nCount = BitConverter.ToInt32(byLen, 0); nCount = BitConverter.ToInt32(byLen, 0);
byData = new byte[8]; byData = new byte[8];
for (int i = 0; i < nCount; i++) { for (int i = 0; i < nCount; i++) {
s.Read(byData, 0, byData.Length); gs.Read(byData, 0, byData.Length);
long id = BitConverter.ToInt64(byData, 0); long id = BitConverter.ToInt64(byData, 0);
long op_out = id >> 32; long op_out = id >> 32;
long op_in = (int)id; long op_in = (int)id;
@ -1832,10 +1844,15 @@ namespace ST.Library.UI
} }
this.ScaleCanvas(scale, 0, 0); this.ScaleCanvas(scale, 0, 0);
this.MoveCanvas(x, y, false, CanvasMoveArgs.All); this.MoveCanvas(x, y, false, CanvasMoveArgs.All);
this.BuildBounds();
} }
this.BuildBounds();
foreach (STNode node in this._Nodes) node.OnEditorLoadCompleted();
}
private STNode GetNodeFromData(byte[] byData) { private STNode GetNodeFromData(byte[] byData) {
int nIndex = 0; int nIndex = 0;
string strModel = Encoding.UTF8.GetString(byData, nIndex + 1, byData[nIndex]);
nIndex += byData[nIndex] + 1;
string strGUID = Encoding.UTF8.GetString(byData, nIndex + 1, byData[nIndex]); string strGUID = Encoding.UTF8.GetString(byData, nIndex + 1, byData[nIndex]);
nIndex += byData[nIndex] + 1; nIndex += byData[nIndex] + 1;
@ -1854,7 +1871,7 @@ namespace ST.Library.UI
nIndex += nLen; nIndex += nLen;
dic.Add(strKey, byValue); dic.Add(strKey, byValue);
} }
if (!m_dic_type.ContainsKey(strGUID)) throw new TypeLoadException("无法找到类型 {" + strGUID + "} 所在程序集 确保所需程序集已被编辑器正确加载 可通过调用LoadAssembly()加载程序集"); if (!m_dic_type.ContainsKey(strGUID)) throw new TypeLoadException("无法找到类型 {" + strGUID + "} 所在程序集 确保程序集{" + strModel + "}已被编辑器正确加载 可通过调用LoadAssembly()加载程序集");
Type t = m_dic_type[strGUID]; ; Type t = m_dic_type[strGUID]; ;
STNode node = (STNode)Activator.CreateInstance(t); STNode node = (STNode)Activator.CreateInstance(t);
node.OnLoadNode(dic); node.OnLoadNode(dic);

View File

@ -103,7 +103,16 @@ namespace ST.Library.UI
/// </summary> /// </summary>
public int DotSize { public int DotSize {
get { return _DotSize; } get { return _DotSize; }
protected internal set { _DotSize = value; } protected set { _DotSize = value; }
}
private Rectangle _TextRectangle;
/// <summary>
/// 获取当前 Option 文本区域
/// </summary>
public Rectangle TextRectangle {
get { return _TextRectangle; }
internal set { _TextRectangle = value; }
} }
private object _Data; private object _Data;

View File

@ -220,5 +220,12 @@ namespace ST.Library.UI
IEnumerator IEnumerable.GetEnumerator() { IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator(); return this.GetEnumerator();
} }
public STNodeOption[] ToArray() {
STNodeOption[] ops = new STNodeOption[this._Count];
for (int i = 0; i < ops.Length; i++)
ops[i] = m_options[i];
return ops;
}
} }
} }

Binary file not shown.

View File

@ -41,8 +41,8 @@ namespace ST.Library.UI.Demo_Image
return m_sz; return m_sz;
} }
protected override Point OnSetOptionLocation(STNodeOption op) { protected override Point OnSetOptionDotLocation(STNodeOption op, Point pt) {
return new Point(op.DotLeft, this.Top + 35); return new Point(pt.X, pt.Y + 10);
//return base.OnSetOptionLocation(op); //return base.OnSetOptionLocation(op);
} }

View File

@ -80,8 +80,8 @@ namespace ST.Library.UI
OpenFileDialog ofd = new OpenFileDialog(); OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "*.stn|*.stn"; ofd.Filter = "*.stn|*.stn";
if (ofd.ShowDialog() != DialogResult.OK) return; if (ofd.ShowDialog() != DialogResult.OK) return;
stNodeEditor1.LoadCanvas(ofd.FileName);
stNodeEditor1.Nodes.Clear(); stNodeEditor1.Nodes.Clear();
stNodeEditor1.LoadCanvas(ofd.FileName);
} }
} }
} }

96
WinNodeEditerTest/Form2.Designer.cs generated Executable file
View File

@ -0,0 +1,96 @@
namespace ST.Library.UI
{
partial class Form2
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.button4 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(0, 0);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(0, 29);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 1;
this.button2.Text = "button2";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Location = new System.Drawing.Point(0, 58);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(75, 23);
this.button3.TabIndex = 2;
this.button3.Text = "button3";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// button4
//
this.button4.Location = new System.Drawing.Point(0, 87);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(75, 23);
this.button4.TabIndex = 3;
this.button4.Text = "button4";
this.button4.UseVisualStyleBackColor = true;
this.button4.Click += new System.EventHandler(this.button4_Click);
//
// Form2
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.button4);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form2";
this.Text = "Form2";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
}
}

36
WinNodeEditerTest/Form2.cs Executable file
View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ST.Library.UI
{
public partial class Form2 : Form
{
public Form2() {
InitializeComponent();
}
Graphics m_g;
private void button1_Click(object sender, EventArgs e) {
m_g = this.CreateGraphics();
}
private void button2_Click(object sender, EventArgs e) {
m_g.DrawRectangle(Pens.Red, 10, 10, 30, 30);
}
private void button3_Click(object sender, EventArgs e) {
m_g.DrawRectangle(Pens.Yellow, 45, 45, 20, 20);
}
private void button4_Click(object sender, EventArgs e) {
this.CreateGraphics().FillRectangle(Brushes.Black, 20, 20, 20, 20);
}
}
}

120
WinNodeEditerTest/Form2.resx Executable file
View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -28,7 +28,7 @@ namespace ST.Library.UI
//当有数据传入时 //当有数据传入时
void m_in_num_DataTransfer(object sender, STNodeOptionEventArgs e) { void m_in_num_DataTransfer(object sender, STNodeOptionEventArgs e) {
//判断连线是否是连接状态(建立连线 断开连线 都会触发该事件) //判断连线是否是连接状态(建立连线 断开连线 都会触发该事件)
if (e.Status == ConnectionStatus.Connected) { if (e.Status == ConnectionStatus.Connected && e.TargetOption.Data != null) {
if (sender == m_in_num1) if (sender == m_in_num1)
m_nNum1 = (int)e.TargetOption.Data;//TargetOption为触发此事件的Option m_nNum1 = (int)e.TargetOption.Data;//TargetOption为触发此事件的Option
else else

View File

@ -64,6 +64,12 @@
<Compile Include="Form1.Designer.cs"> <Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon> <DependentUpon>Form1.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Form2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form2.Designer.cs">
<DependentUpon>Form2.cs</DependentUpon>
</Compile>
<Compile Include="NodeNumberAdd.cs" /> <Compile Include="NodeNumberAdd.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
@ -73,6 +79,9 @@
<EmbeddedResource Include="Form1.resx"> <EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon> <DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Form2.resx">
<DependentUpon>Form2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>

View File

@ -88,7 +88,7 @@
</ul> </ul>
</li> </li>
</ul> </ul>
<span style="background-color:blueviolet;font-size:12px;text-align:center;width:100%;display:inline-block;">最后编辑时间 2020-12-30</span> <span style="background-color:blueviolet;font-size:12px;text-align:center;width:100%;display:inline-block;">最后编辑时间 2021-01-21</span>
</div> </div>
<div id="div_right"> <div id="div_right">
<h2 class="anchor_point" anchor="a">概述</h2> <h2 class="anchor_point" anchor="a">概述</h2>
@ -595,21 +595,40 @@
<tr style="background-color:#505050"><td colspan="2">void OnDrawMark(DrawingTools dt)</td></tr> <tr style="background-color:#505050"><td colspan="2">void OnDrawMark(DrawingTools dt)</td></tr>
<tr> <tr>
<td>dt</td><td>绘制工具</td> <td>dt</td><td>绘制工具</td>
</tr> </tr><tr><td colspan="2" style="background-color:#343434">&nbsp;</td></tr>
<tr><td colspan="2" style="background-color:#343434">&nbsp;</td></tr>
<tr style="background-color:#505050"><td colspan="2">当计算Option位置时候发生</td></tr>
<tr style="background-color:#505050"><td colspan="2">Point OnSetOptionLocation(STNodeOption op)</td></tr>
<tr>
<td>op</td><td>需要计算的Option</td>
</tr>
<tr><td colspan="2" style="background-color:#343434">&nbsp;</td></tr>
<tr style="background-color:#505050"><td colspan="2">绘制选项连线的点</td></tr> <tr style="background-color:#505050"><td colspan="2">绘制选项连线的点</td></tr>
<tr style="background-color:#505050"><td colspan="2">void OnDrawOptionDot(DrawingTools dt, STNodeOption op)</td></tr> <tr style="background-color:#505050"><td colspan="2">void OnDrawOptionDot(DrawingTools dt, STNodeOption op)</td></tr>
<tr> <tr>
<td>dt</td><td>绘制工具</td> <td>dt</td><td>绘制工具</td>
</tr> </tr>
<tr> <tr>
<td>op</td><td>指定的选项</td> <td>op</td><td>需要绘制的Option</td>
</tr></tr><tr><td colspan="2" style="background-color:#343434">&nbsp;</td></tr>
<tr style="background-color:#505050"><td colspan="2">绘制选项的文本</td></tr>
<tr style="background-color:#505050"><td colspan="2">void OnDrawOptionText(DrawingTools dt, STNodeOption op)</td></tr>
<tr>
<td>dt</td><td>绘制工具</td>
<tr/>
<tr>
<td>op</td><td>需要绘制的Option</td>
</tr>
<tr><td colspan="2" style="background-color:#343434">&nbsp;</td></tr>
<tr style="background-color:#505050"><td colspan="2">当计算Option连线点位置时候发生</td></tr>
<tr style="background-color:#505050"><td colspan="2">Point OnSetOptionDotLocation(STNodeOption op, Point pt)</td></tr>
<tr>
<td>op</td><td>需要计算的Option</td>
</tr>
<tr>
<td>op</td><td>自动计算出的位置</td>
</tr>
<tr><td colspan="2" style="background-color:#343434">&nbsp;</td></tr>
<tr style="background-color:#505050"><td colspan="2">当计算Option文本区域时候发生</td></tr>
<tr style="background-color:#505050"><td colspan="2">Rectangle OnSetOptionTextRectangle(STNodeOption op, Rectangle rect)</td></tr>
<tr>
<td>op</td><td>需要计算的Option</td>
</tr>
<tr>
<td>op</td><td>自动计算出的区域</td>
</tr> </tr>
<tr><td colspan="2" style="background-color:#343434">&nbsp;</td></tr> <tr><td colspan="2" style="background-color:#343434">&nbsp;</td></tr>
<tr style="background-color:#505050"><td colspan="2">计算当前Node所需要的矩形区域</td></tr> <tr style="background-color:#505050"><td colspan="2">计算当前Node所需要的矩形区域</td></tr>
@ -634,13 +653,18 @@
</tr> </tr>
<tr style="background-color:#505050"><td colspan="2">当需要保存时候 此Node有哪些需要额外保存的数据</td></tr> <tr style="background-color:#505050"><td colspan="2">当需要保存时候 此Node有哪些需要额外保存的数据</td></tr>
<tr style="background-color:#505050"><td colspan="2">void OnSaveNode(Dictionary&lt;string, byte[]&gt;)</td></tr> <tr style="background-color:#505050"><td colspan="2">void OnSaveNode(Dictionary&lt;string, byte[]&gt;)</td></tr>
<tr><td colspan="2" style="background-color:#343434"><span style="color:orangered">保存时并不会进行序列化 仅自动保存<span class="span_property">Mark</span>属性 还原时候仅重新通过空参数构造器创建此Node <tr>
<td>dic</td><td>需要保存的数据</td>
</tr>
<tr><td colspan="2" style="background-color:#343434"><span style="color:orangered">保存时并不会进行序列化 仅自动保存部分(<span class="span_property">Guid,Left,Top,Mark,LockOption,LockLocation</span>)属性 还原时候仅重新通过空参数构造器创建此Node
<br/>然后调用<span class="span_property">OnLoadNode()</span>将保存的数据进行还原</span></td></tr> <br/>然后调用<span class="span_property">OnLoadNode()</span>将保存的数据进行还原</span></td></tr>
<tr style="background-color:#505050"><td colspan="2">void OnLoadNode(Dictionary<string, byte[]> dic)</td></tr> <tr style="background-color:#505050"><td colspan="2">void OnLoadNode(Dictionary&lt;string, byte[]&gt; dic)</td></tr>
<tr> <tr>
<td>dic</td><td>保存时候的数据</td> <td>dic</td><td>保存时候的数据</td>
</tr> </tr>
<tr><td colspan="2" style="background-color:#343434">&nbsp;</td></tr> <tr><td colspan="2" style="background-color:#343434">&nbsp;</td></tr>
<tr style="background-color:#505050"><td colspan="2">当编辑器加载完成所有的节点时候发生</td></tr>
<tr style="background-color:#505050"><td colspan="2">void OnEditorLoadCompleted()</td></tr>
</table> </table>
<div style="overflow:auto;margin:0px 10px;max-width:100%;"><pre><span style="color:cornflowerblue">protected override void</span> OnSaveNode(<span style="color:cyan">Dictionary</span>&lt;<span style="color:cornflowerblue">string</span>, <span style="color:cornflowerblue">byte</span>[]&gt;) { <div style="overflow:auto;margin:0px 10px;max-width:100%;"><pre><span style="color:cornflowerblue">protected override void</span> OnSaveNode(<span style="color:cyan">Dictionary</span>&lt;<span style="color:cornflowerblue">string</span>, <span style="color:cornflowerblue">byte</span>[]&gt;) {
dic.Add(<span style="color:lime">"count"</span>, <span style="color:cyan">BitConverter</span>.GetBytes(<span style="color:cornflowerblue">this</span>.InputOptionsCount)); dic.Add(<span style="color:lime">"count"</span>, <span style="color:cyan">BitConverter</span>.GetBytes(<span style="color:cornflowerblue">this</span>.InputOptionsCount));