create project
55
.gitignore
vendored
@ -1,52 +1,3 @@
|
|||||||
# Prerequisites
|
/Bin
|
||||||
*.d
|
bin/
|
||||||
|
obj/
|
||||||
# Object files
|
|
||||||
*.o
|
|
||||||
*.ko
|
|
||||||
*.obj
|
|
||||||
*.elf
|
|
||||||
|
|
||||||
# Linker output
|
|
||||||
*.ilk
|
|
||||||
*.map
|
|
||||||
*.exp
|
|
||||||
|
|
||||||
# Precompiled Headers
|
|
||||||
*.gch
|
|
||||||
*.pch
|
|
||||||
|
|
||||||
# Libraries
|
|
||||||
*.lib
|
|
||||||
*.a
|
|
||||||
*.la
|
|
||||||
*.lo
|
|
||||||
|
|
||||||
# Shared objects (inc. Windows DLLs)
|
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.so.*
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Executables
|
|
||||||
*.exe
|
|
||||||
*.out
|
|
||||||
*.app
|
|
||||||
*.i*86
|
|
||||||
*.x86_64
|
|
||||||
*.hex
|
|
||||||
|
|
||||||
# Debug files
|
|
||||||
*.dSYM/
|
|
||||||
*.su
|
|
||||||
*.idb
|
|
||||||
*.pdb
|
|
||||||
|
|
||||||
# Kernel Module Compile Results
|
|
||||||
*.mod*
|
|
||||||
*.cmd
|
|
||||||
.tmp_versions/
|
|
||||||
modules.order
|
|
||||||
Module.symvers
|
|
||||||
Mkfile.old
|
|
||||||
dkms.conf
|
|
||||||
|
BIN
Document/back.png
Executable file
After Width: | Height: | Size: 12 KiB |
185
Document/css/doc.css
Executable file
@ -0,0 +1,185 @@
|
|||||||
|
@charset "utf-8";
|
||||||
|
*{
|
||||||
|
color:rgba(255,255,255,.7);
|
||||||
|
font-family:"consolas","Menlo","DejaVu Sans Mono","monaco","MonoSpace","courier new","微软雅黑","Microsoft Yahei";
|
||||||
|
font-weight:300;
|
||||||
|
background-repeat:no-repeat;
|
||||||
|
/*text-shadow:0px 1px 1px #DDD;*/
|
||||||
|
-webkit-font-smoothing:antialiased;
|
||||||
|
}
|
||||||
|
::selection { background-color: #5B6B8545; }
|
||||||
|
::-moz-selection { background-color: #5B6B8545; }
|
||||||
|
::-webkit-selection { background-color: #5B6B8545; }
|
||||||
|
hr{
|
||||||
|
height: 1px;
|
||||||
|
border: none;
|
||||||
|
margin: 10px;
|
||||||
|
border-top: solid 1px #2b2b2b;
|
||||||
|
}
|
||||||
|
body{
|
||||||
|
margin:0px;
|
||||||
|
position:relative;
|
||||||
|
font-size:14px;
|
||||||
|
background-color:#343434;
|
||||||
|
}
|
||||||
|
h2{
|
||||||
|
margin:0px 10px;
|
||||||
|
padding-left:10px;
|
||||||
|
border-left:solid 5px #0096C9;
|
||||||
|
border-top:solid 1px #2b2b2b;
|
||||||
|
border-bottom:solid 1px #2b2b2b;
|
||||||
|
font-weight:bold;
|
||||||
|
background-color:#505050;
|
||||||
|
height:38px;
|
||||||
|
line-height:38px;
|
||||||
|
}
|
||||||
|
p{margin:10px 25px;}
|
||||||
|
a{
|
||||||
|
color:#58b4e8;
|
||||||
|
cursor:pointer;
|
||||||
|
outline:none;
|
||||||
|
text-decoration:none;
|
||||||
|
}
|
||||||
|
a:hover{
|
||||||
|
color:#58b4e8;
|
||||||
|
outline-style:none;
|
||||||
|
}
|
||||||
|
table{
|
||||||
|
margin:20px;
|
||||||
|
color: rgba(255,255,255,.7);
|
||||||
|
font-size: 12px;
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-top: solid 1px #1f1f1f;
|
||||||
|
border-left: solid 1px #1f1f1f;
|
||||||
|
background-color: #2b2b2b;
|
||||||
|
}
|
||||||
|
td{
|
||||||
|
padding: 5px 20px;
|
||||||
|
border-right: solid 1px #1f1f1f;
|
||||||
|
border-bottom: solid 1px #1f1f1f;
|
||||||
|
}
|
||||||
|
pre{
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
font-size: 12px;
|
||||||
|
overflow: auto;
|
||||||
|
padding:10px;
|
||||||
|
display:inline-block;
|
||||||
|
margin-top:0px;
|
||||||
|
min-width:680px;
|
||||||
|
}
|
||||||
|
.span_center{
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #0096c9;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 1px 5px;
|
||||||
|
color: white;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.span_title{
|
||||||
|
margin-left:10px;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: dodgerblue;
|
||||||
|
padding: 2px 10px;
|
||||||
|
/* border-radius: 5px; */
|
||||||
|
font-size: 12px;
|
||||||
|
position: relative;
|
||||||
|
height: 20pxpx;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
.span_title:after{
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
border-left: solid 13px #2090ff;
|
||||||
|
border-top: solid 12px transparent;
|
||||||
|
border-bottom: solid 12px transparent;
|
||||||
|
right: -13px;
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
|
.span_property{
|
||||||
|
color:white;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: gray;
|
||||||
|
padding: 1px 4px;
|
||||||
|
margin:0px 4px;
|
||||||
|
}
|
||||||
|
#div_body{
|
||||||
|
|
||||||
|
}
|
||||||
|
#div_left{
|
||||||
|
overflow:auto;
|
||||||
|
height:100%;
|
||||||
|
width:220px;
|
||||||
|
position:fixed;
|
||||||
|
background-color:#343434;
|
||||||
|
border-right:solid 1px black;
|
||||||
|
}
|
||||||
|
.ul_group_root a{
|
||||||
|
color:gray;
|
||||||
|
font-weight:300px;
|
||||||
|
height:30px;
|
||||||
|
line-height:30px;
|
||||||
|
display:block;
|
||||||
|
padding:5px 15px;
|
||||||
|
transition:background-color .5s;
|
||||||
|
}
|
||||||
|
.ul_group_root a:hover{
|
||||||
|
color:white;
|
||||||
|
background-color:deepskyblue;
|
||||||
|
transition:background-color 0s;
|
||||||
|
}
|
||||||
|
.ul_group_root,.ul_group_root ul{
|
||||||
|
margin:0px;
|
||||||
|
padding:0px;
|
||||||
|
list-style:none;
|
||||||
|
font-size:12px;
|
||||||
|
background-color:#1A1A1A;
|
||||||
|
}
|
||||||
|
.a_node_root{
|
||||||
|
color:gray;
|
||||||
|
font-size:14px;
|
||||||
|
padding:5px;
|
||||||
|
display:block;
|
||||||
|
background-color:#343434;
|
||||||
|
/*border-top:1px solid #1A1A1A;
|
||||||
|
border-bottom:1px solid #1A1A1A;
|
||||||
|
background-color:rgba(255,255,255,0.05);*/
|
||||||
|
}
|
||||||
|
.anchor_btn{
|
||||||
|
transition:background-color 1s;
|
||||||
|
}
|
||||||
|
.anchor_btn.active{
|
||||||
|
color:white;
|
||||||
|
background-color:#0076A0;
|
||||||
|
transition:background-color 0s;
|
||||||
|
}
|
||||||
|
.li_node_sub{
|
||||||
|
text-align:right;
|
||||||
|
}
|
||||||
|
#div_right{
|
||||||
|
margin-left:220px;
|
||||||
|
}
|
||||||
|
#div_right a{
|
||||||
|
color: white;
|
||||||
|
margin: 2px;
|
||||||
|
padding: 1px 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
display: inline-block;
|
||||||
|
font-size:12px;
|
||||||
|
background-color: rgba(0,150,201,.2);
|
||||||
|
border:solid 1px #0096C9;
|
||||||
|
}
|
||||||
|
#div_right ul{
|
||||||
|
list-style:none;
|
||||||
|
margin:5px;
|
||||||
|
padding:0px 10px;
|
||||||
|
}
|
||||||
|
#div_img_node{
|
||||||
|
text-align:center;
|
||||||
|
margin:0px 10px;
|
||||||
|
background-color:black;
|
||||||
|
}
|
||||||
|
#div_img_node img{
|
||||||
|
width:50%;
|
||||||
|
max-width:537px;
|
||||||
|
}
|
93
Document/css/index.css
Executable file
@ -0,0 +1,93 @@
|
|||||||
|
@charset "utf-8";
|
||||||
|
*{
|
||||||
|
font-family:"consolas","Menlo","DejaVu Sans Mono","monaco","MonoSpace","courier new","微软雅黑","Microsoft Yahei";
|
||||||
|
font-weight:300;
|
||||||
|
background-repeat:no-repeat;
|
||||||
|
text-shadow:0px 1px 1px #DDD;
|
||||||
|
-webkit-font-smoothing:antialiased;
|
||||||
|
}
|
||||||
|
::selection { background-color: #5B6B8545; }
|
||||||
|
::-moz-selection { background-color: #5B6B8545; }
|
||||||
|
::-webkit-selection { background-color: #5B6B8545; }
|
||||||
|
a{
|
||||||
|
outline:none;
|
||||||
|
text-decoration:none;
|
||||||
|
}
|
||||||
|
p{line-height:25px;}
|
||||||
|
img{max-width:100%;}
|
||||||
|
ul{margin:0px;padding-left:20px;}
|
||||||
|
li{margin:5px;}
|
||||||
|
hr{
|
||||||
|
height: 1px;
|
||||||
|
border: none;
|
||||||
|
margin: 30px 0px;
|
||||||
|
border-top: solid 1px lightgray;
|
||||||
|
}
|
||||||
|
body{
|
||||||
|
margin:0px;
|
||||||
|
position:relative;
|
||||||
|
font-size:14px;
|
||||||
|
}
|
||||||
|
#div_body{
|
||||||
|
max-width:1074px;
|
||||||
|
margin: 0 auto;
|
||||||
|
box-shadow: 0px 0px 20px #222;
|
||||||
|
}
|
||||||
|
#div_img_node{
|
||||||
|
text-align:center;
|
||||||
|
font-size:0px;
|
||||||
|
overflow:hidden;
|
||||||
|
background-color:cornflowerblue;
|
||||||
|
}
|
||||||
|
#div_img_node img{
|
||||||
|
width:50%;
|
||||||
|
max-width:537px;
|
||||||
|
box-shadow: 0px 0px 20px #222;
|
||||||
|
}
|
||||||
|
.span_title{
|
||||||
|
font-size:40px;
|
||||||
|
display:inline-block;
|
||||||
|
margin:20px;
|
||||||
|
text-align:center;
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
.span_title:before{
|
||||||
|
content: 'Copyright© DebugST@Crystal_lz';
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 100%;
|
||||||
|
font-size: 11px;
|
||||||
|
color: gray;
|
||||||
|
width:100%;
|
||||||
|
transform: translate(-50%, 0px);
|
||||||
|
}
|
||||||
|
.span_title:after{
|
||||||
|
content: '(V 1.0)';
|
||||||
|
font-size: 10px;
|
||||||
|
position: absolute;
|
||||||
|
background-color: hotpink;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 2px;
|
||||||
|
color: white;
|
||||||
|
display: block;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
transform: translate(50%, -50%);
|
||||||
|
}
|
||||||
|
.a_top_btn{
|
||||||
|
color:white;
|
||||||
|
padding: 5px 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 15px;
|
||||||
|
background-color: cornflowerblue;
|
||||||
|
margin:0px 10px;
|
||||||
|
display:inline-block;
|
||||||
|
}
|
||||||
|
.span_note{
|
||||||
|
color:cornflowerblue;
|
||||||
|
margin: 2px;
|
||||||
|
padding: 2px 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #EEE;
|
||||||
|
border:solid 1px #DDD;
|
||||||
|
}
|
903
Document/doc.html
Executable file
@ -0,0 +1,903 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>STNodeEditor Document</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./css/doc.css"/>
|
||||||
|
<script type="text/javascript" src="./js/jquery-1.10.2.min.js"></script>
|
||||||
|
<script type="text/javascript" src="./js/doc.js"></script>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
$(".anchor_btn").click(function(){
|
||||||
|
var nTop = $(".anchor_point[anchor='" + $(this).attr('anchor') + "']").offset().top;
|
||||||
|
if(!$(this).hasClass("a_node_root")) nTop -= 5;
|
||||||
|
$('html,body').animate({scrollTop:nTop},500);
|
||||||
|
});
|
||||||
|
$(window).scroll(function(){
|
||||||
|
var nMin = 100000,strName = '';
|
||||||
|
var nHeight = document.body.clientHeight;
|
||||||
|
var nHtmlTop = $(this).scrollTop();
|
||||||
|
var es = $('.anchor_point');
|
||||||
|
for(i = 0; i < es.length; i++){
|
||||||
|
var nSub = Math.abs(es[i].offsetTop - nHtmlTop);
|
||||||
|
if(nSub < nMin){
|
||||||
|
nMin = nSub;
|
||||||
|
if(nHtmlTop + (nHeight / 2) >= es[i].offsetTop)
|
||||||
|
strName = $(es[i]).attr('anchor');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if(nMin > 100) return;
|
||||||
|
$(".anchor_btn").removeClass('active');
|
||||||
|
$(".anchor_btn[anchor='" + strName + "']").addClass('active');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="div_body">
|
||||||
|
<div id="div_left">
|
||||||
|
<ul class="ul_group_root">
|
||||||
|
<li>
|
||||||
|
<a class="a_node_root anchor_btn active" anchor="a">概述</a>
|
||||||
|
<ul>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="b">节点编辑器</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="a_node_root anchor_btn" anchor="c">STNodeEditor</a>
|
||||||
|
<ul>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="d">属性</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="e">受保护字段</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="f">可重载函数</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="g">公开函数</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="h">事件</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="a_node_root anchor_btn" anchor="i">STNode</a>
|
||||||
|
<ul>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="j">属性</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="k">受保护字段</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="l">可重载函数</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="m">其他重载函数</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="n">公开函数</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="o">关于重绘</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="a_node_root anchor_btn" anchor="p">STNodeOption</a>
|
||||||
|
<ul>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="q">属性</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="r">受保护字段</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="s">构造器</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="t">可重载函数</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="u">公开函数</a></li>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="v">事件</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="a_node_root anchor_btn" anchor="w">STNodeOptionEventArgs</a>
|
||||||
|
<ul>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="x">属性</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="a_node_root anchor_btn" anchor="y">STNodeControl</a>
|
||||||
|
<ul>
|
||||||
|
<li class="li_node_sub"><a class="anchor_btn" anchor="z">Demo</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<span style="background-color:blueviolet;font-size:12px;text-align:center;width:100%;display:inline-block;">最后编辑时间 2020-12-30</span>
|
||||||
|
</div>
|
||||||
|
<div id="div_right">
|
||||||
|
<h2 class="anchor_point" anchor="a">概述</h2>
|
||||||
|
<p>那是一个冬季 在研究无线电安全的作者接触到了<a target="_bank" href="https://www.gnuradio.org/">GNURadio</a> 那是作者第一次接触到节点编辑器<br/> "What? Excuse me... What's this?.. 这是什么鬼东西?..."</p>
|
||||||
|
<p>那是一个春季 不知道为什么 过完年整个世界都变了 大家被迫窝在家里 无聊至极的作者学起了<a target="_bank" href="https://www.blender.org/">Blender</a> 那是作者第二次接触到节点编辑器<br/> "Wo...原来这东西可以这么玩...真方便"<br/> 于是一些想法在作者脑中逐渐诞生 让作者有了想做一个这样的东西的想法</p>
|
||||||
|
<p>那是一个夏季 不知道为什么 作者又玩起了<a target="_bank" href="http://www.blackmagicdesign.com/cn/products/davinciresolve/">Davinci</a> 那是作者第三次接触到节点编辑器 这一次的接触让作者对节点编辑器的好感倍增 作者瞬间觉得 只要是可以模块化流程化的功能 万物皆可节点化</p>
|
||||||
|
<hr/>
|
||||||
|
<center><span class="span_center">于是下面的这个东西就诞生了</span></center>
|
||||||
|
<div id="div_img_node"><img src="./images/node.png"/><img src="./images/node.gif"/></div>
|
||||||
|
<center><span class="span_center">或者这样的一个东西</span></center>
|
||||||
|
<div style="text-align:center;margin:0px 10px;background-color:black;"><img style="width:1077px;max-width:100%;" src="./images/channel.png"/></div>
|
||||||
|
<p>本案例中只是提供了一个节点编辑器控件 并不包含节点列表 属性编辑器等 若后期有空再做一套完整的框架</p>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="b">节点编辑器</span>
|
||||||
|
<hr/>
|
||||||
|
<p>或许你未曾接触过节点编辑 但节点编辑的影子越来越多 尤其是在影视相关的一些设计类软件当中 Blender,C4D,Houdini,Davinci 等</p>
|
||||||
|
<p>节点编辑最大的好处就是可视化操作 将单一的功能点封装到节点之中 让用户通过节点布线来组合自己需要的逻辑 让整个流程可视化 而不是将你程序的整个执行流程固化在你的程序之中 当然在这之前你需要定义好节点的数据类型 <span style="color:orangered">因为数据类型无法兼容是不允许连线的</span> 通常情况下同颜色的连接点表示数据类型相同</p>
|
||||||
|
<p>另一个好处 让开发者只需要注重单一的功能点开发 使得功能与功能之间的耦合度降低 开发者在节点中开发完成需要的功能 无需知道应该把数据交给谁或者怎么去传递数据 只需要将你的结果数据打包给你所继承的节点类 节点编辑器会自动完成数据的投递过程
|
||||||
|
</p>
|
||||||
|
<h2 class="anchor_point" anchor="c">STNodeEditor</h2>
|
||||||
|
<p>STNodeEditor为节点容器 其中最重要的一个属性为<span class="span_property">Nodes</span>里面包含了画布中能看到的所有节点</p>
|
||||||
|
<p>STNodeEditor有两套坐标系统 平常情况下使用最多的就直接是控件的坐标系统 需要在控件的什么位置绘图或者添加东西采用的都是相对控件左上角的坐标 但是在节点编辑器中的情况比较复杂 需要引入一个画布的概念 画布是可以移动缩放的 所以在绘图的时候依旧采用控件的坐标系统将带来很多的麻烦 所以为画布定义了一个坐标原点 在节点以及连线绘制的时候采用的是画布的坐标系统 当需要拖动画布位置的时候 改变画布原点的位置就好了 而内部节点的位置依旧不做变更 因为节点采用的坐标位置是相对画布原点的
|
||||||
|
<br/><span style="color:orangered">当画布中<span class="span_property">Nodes</span>没有元素时候 画布将处于重置状态无法缩放与移动 因为作者觉得这样的操作没有任何意义</span></p>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="d">属性</span>
|
||||||
|
<hr/>
|
||||||
|
<table>
|
||||||
|
<tr style="text-align:center;background-color:#505050;">
|
||||||
|
<td>属性名称</td><td>类型</td><td>描述</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>CanvasOffsetX</td><td>float</td><td>获取画布原点相对于控件 X 方向上的偏移位置</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>CanvasOffsetY</td><td>float</td><td>获取画布原点相对于控件 Y 方向上的偏移位置</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>CanvasOffset</td><td>PointF</td><td>获取画布原点相对于控件偏移位置</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>CanvasValidBounds</td><td>Rectangle</td><td>获取画布中的有被用到的有效区域</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>CanvasScale</td><td>float</td><td>获取画布的缩放比例</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Curvature</td><td>float</td><td>获取或设置 Option 之间连线的曲度</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Magnet</td><td>bool</td><td>获取或设置移动画布中 Node 时候 是否启用磁铁效果</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ShowBorder</td><td>bool</td><td>获取或设置移动画布中是否显示 Node 边框</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ShowGrid</td><td>bool</td><td>获取或设置画布中是否绘制背景网格线条</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ShowLocation</td><td>bool</td><td>获取或设置是否在画布边缘显示超出视角的 Node 位置信息</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Nodes</td><td>STNodeCollection</td><td>获取画布中 Node 集合</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ActiveNode</td><td>STNode</td><td>获取当前画布中被选中的活动 Node</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>HoverNode</td><td>STNode</td><td>获取当前画布中鼠标悬停的 Node</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>GridColor</td><td>Color</td><td>获取或设置绘制画布背景时 网格线条颜色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>BorderColor</td><td>Color</td><td>获取或设置画布中 Node 边框颜色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>BorderHoverColor</td><td>Color</td><td>获取或设置画布中悬停 Node 边框颜色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>BorderSelectColor</td><td>Color</td><td>获取或设置画布中选中 Node 边框颜色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>BorderActiveColor</td><td>Color</td><td>获取或设置画布中活动 Node 边框颜色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>MarkForeColor</td><td>Color</td><td>获取或设置画布绘制 Node 标记详情采用的前景色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>MarkBackColor</td><td>Color</td><td>获取或设置画布绘制 Node 标记详情采用的背景色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>MagnetLineColor</td><td>Color</td><td>获取或设置画布中移动 Node 时候 磁铁标记线颜色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SelectedRectangleColor</td><td>Color</td><td>获取或设置画布中选择矩形区域的颜色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>HighLineColor</td><td>Color</td><td>获取或设置画布中高亮连线的颜色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>LocationForeColor</td><td>Color</td><td>获取或设置画布中边缘位置提示区域前景色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>LocationBackColor</td><td>Color</td><td>获取或设置画布中边缘位置提示区域背景色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>UnknownTypeColor</td><td>Color</td><td>获取或设置画布中当 Node 中 Option 数据类型无法确定时应当使用的颜色</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>TypeColor</td><td>Dictionary<Type, Color></td><td>获取或设置画布中 Node 中 Option 数据类型预设颜色</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<span class="span_title anchor_point" anchor="e">受保护字段</span>
|
||||||
|
<table>
|
||||||
|
<tr style="text-align:center;background-color:#505050;">
|
||||||
|
<td>属性名称</td><td>类型</td><td>描述</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>m_pt_in_control</td><td>Point</td><td>当前鼠标在控件中的实时位置</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>m_pt_in_canvas</td><td>PointF</td><td>当前鼠标在画布中的实时位置</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>m_pt_down_in_control</td><td>Point</td><td>鼠标点击时在控件上的位置</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>m_pt_down_in_canvas</td><td>PointF</td><td>鼠标点击时在画布中的位置</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>m_pt_canvas_old</td><td>PointF</td><td>用于鼠标点击移动画布时候 鼠标点下时候的画布坐标位置</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>m_pt_dot_down</td><td>Point</td><td>用于保存连线过程中保存点下 Option 的起点坐标</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>m_option_down</td><td>STNodeOption</td><td>用于保存连线过程中鼠标点下的起点Option 当MouseUp时候 确定是否连接此节点</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="span_property" style="background-color:#0090c9;">TypeColor</span>
|
||||||
|
<ul>
|
||||||
|
<li>此属性为当前<span class="span_property">STNodeEditor</span>中所有的数据类型所对应的颜色 节点中所有的数据类型都应当包含在此集合中 即便有动态需要加载的未知类型的节点 那么对应的节点也应该在节点的<span class="span_property">OnOwnerChanged()</span>中向容器提交自己数据类型以及对应颜色
|
||||||
|
<br/><span style="color:orangered;">若节点有单独对<span class="span_property">STNodeOption.DotColor</span>设置值 则忽略该对照表中的颜色 即不为默认颜色<span class="span_property">Color.Transparent</span></span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<hr/>
|
||||||
|
<li>
|
||||||
|
<span class="span_property" style="background-color:#0090c9">UnknownTypeColor</span>
|
||||||
|
<ul>
|
||||||
|
<li>若节点中并没有单独设置数据类型颜色且在<span class="span_property">TypeColor</span>中无法匹配时候采用此值 所以将此特殊类型单独设置</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<hr/><span class="span_title anchor_point" anchor="f">可重载函数</span><hr/>
|
||||||
|
<table>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当绘制背景网格线时候发生</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawGrid(DrawingTools dt, int nWidth, int nHeight)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>nWidth</td><td>需要绘制宽度</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>nHeight</td><td>需要绘制高度</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当绘制 Node 时候发生</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawNode(DrawingTools dt, Rectangle rect)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>rect</td><td>可视画布区域大小</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当绘制已连接路径时候发生</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawConnectedLine(DrawingTools dt)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当绘制 Mark 详情信息时候发生</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawMark(DrawingTools dt)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当移动 Node 时候 需要显示对齐参考线时候发生</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawMagnetLine(DrawingTools dt, MagnetInfo mi)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>mi</td><td>匹配的磁铁信息</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">绘制选择的矩形区域</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawSelectedRectangle(DrawingTools dt, RectangleF rectf)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>rectf</td><td>位于控件上的矩形区域</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">绘制超出视觉区域的 Node 位置提示信息</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawNodeOutLocation(DrawingTools dt, Size sz, List<Point> lstPts)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>sz</td><td>提示框边距</td>
|
||||||
|
<tr>
|
||||||
|
<td>lstPts</td><td>超出视觉区域的 Node 位置信息</td>
|
||||||
|
</tr>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">绘制提示信息</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawAlert(DrawingTools dt, Rectangle rect, string strText, Color foreColor, Color backColor, AlertLocation al)</td></tr>
|
||||||
|
<tr><td>dt</td><td>绘制工具</td></tr>
|
||||||
|
<tr><td>rect</td><td>需要绘制区域</td></tr>
|
||||||
|
<tr><td>strText</td><td>需要绘制文本</td></tr>
|
||||||
|
<tr><td>foreColor</td><td>信息前景色</td></tr>
|
||||||
|
<tr><td>backColor</td><td>信息背景色</td></tr>
|
||||||
|
<tr><td>al</td><td>信息位置</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">获取提示信息需要绘制的矩形区域</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">Rectangle GetAlertRectangle(Graphics g, string strText, AlertLocation al)</td></tr>
|
||||||
|
<tr><td>g</td><td>绘图表面</td></tr>
|
||||||
|
<tr><td>strText</td><td>需要绘制文本</td></tr>
|
||||||
|
<tr><td>al</td><td>信息位置</td></tr>
|
||||||
|
</table>
|
||||||
|
<span class="span_title anchor_point" anchor="g">公开函数</span>
|
||||||
|
<table>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">通过画布坐标进行寻找</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">NodeFindInfo FindNodeFromPoint(PointF pt)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>pt</td><td>画布中的坐标</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">获取已经被选择的 Node 集合</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">STNode[] GetSelectedNode()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">将画布坐标转换为控件坐标</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">float CanvasToControl(XXX xxx)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>xxx</td><td>Rectangle,RectangleF,Point,PointF...</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">将控件坐标转换为画布坐标</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">float ControlToCanvas(XXX xxx)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>xxx</td><td>Rectangle,RectangleF,Point,PointF...</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">移动画布原点坐标到指定的控件坐标位置</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void MoveCanvas(float x, float y, bool bAnimation, CanvasMoveArgs ma)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>x</td><td>X 坐标</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>y</td><td>Y 坐标</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>bAnimation</td><td>移动过程中是否启动动画效果</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ma</td><td>指定需要修改的坐标参数</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">缩放画布</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void ScaleCanvas(float f, float x, float y)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>f</td><td>缩放比例</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>x</td><td>以指定控件坐标 X 为中心进行缩放</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>y</td><td>以指定控件坐标 Y 为中心进行缩放</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">获取当前已连接的 Option 对应关系</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">ConnectionInfo[] GetConnectionInfo()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">判断两个 Node 之间是否存在连接路径</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">static bool CanFindNodePath(STNode nodeStart, STNode nodeFind)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>nodeStart</td><td>起始 Node</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>nodeFind</td><td>目标 Node</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">获取画布中指定矩形区域图像</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">Image GetCanvasImage(Rectangle rect, float fScale)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>rect</td><td>画布中指定的矩形区域</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>fScale</td><td>缩放比例</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">保存画布中的类容到文件中</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void SaveCanvas(string strFileName)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>strFileName</td><td>文件路径</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">保存画布中的类容到数据流</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void SaveCanvas(Stream s)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>s</td><td>数据流对象</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">获取画布中内容二进制数据</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">byte[] GetCanvasData()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">加载程序集</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">bool LoadAssembly(string strFile)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>返回值</td><td>此文件中是否有类型被加载</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">加载程序集</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">int LoadAssembly(string[] strFiles)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>返回值</td><td>存在STNode类型的文件的个数</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"><span style="color:orangered">编辑器中的节点并不一定来自自身程序集 也可能包含在其他程序集中 这时候需提前加载对应程序集 对应的<span class="span_property">STNode</span>才能正确的从文件或者数据中动态加载到画布类容</span></td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">获取当前编辑器中已加载的Node类型</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">Type[] GetTypes()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">从文件中加载数据</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void LoadCanvas(string strFileName)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>strFileName</td><td>文件路径</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">从二进制加载数据</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void LoadCanvas(byte[] byData)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>byData</td><td>二进制数据</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">从数据流中加载数据</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void LoadCanvas(Stream s)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>s</td><td>数据流对象</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">在画布中显示提示信息</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void ShowAlert(string strText, Color foreColor, Color backColor, int nTime, AlertLocation al, bool bRedraw)</td></tr>
|
||||||
|
<tr><td>strText</td><td>要显示的信息</td></tr>
|
||||||
|
<tr><td>foreColor</td><td>信息前景色</td></tr>
|
||||||
|
<tr><td>backColor</td><td>信息背景色</td></tr>
|
||||||
|
<tr><td>nTime</td><td>信息持续时间</td></tr>
|
||||||
|
<tr><td>al</td><td>信息要显示的位置</td></tr>
|
||||||
|
<tr><td>bRedraw</td><td>是否立即重绘</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">设置画布中活动的节点</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">STNode SetActiveNode(STNode node)</td></tr>
|
||||||
|
<tr><td>STNode</td><td>需要被设置为活动的节点</td></tr>
|
||||||
|
<tr><td>返回值</td><td>设置前的活动节点</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">向编辑器中添加默认数据类型颜色</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">SetTypeColor(Type t, Color clr)</td></tr>
|
||||||
|
<tr><td>t</td><td>数据类型</td></tr>
|
||||||
|
<tr><td>clr</td><td>对应颜色</td></tr>
|
||||||
|
</table>
|
||||||
|
<hr/><span class="span_title anchor_point" anchor="h">事件</span><hr/>
|
||||||
|
<table>
|
||||||
|
<tr><td>SelectedChanged</td><td>选择的节点发生变化时候发生</td><tr/>
|
||||||
|
<tr><td>HoverChanged</td><td>悬停的节点发生变化时候发生</td><tr/>
|
||||||
|
<tr><td>NodeAdded</td><td>当节点被添加时候发生</td><tr/>
|
||||||
|
<tr><td>NodeRemoved</td><td>当节点被移除时候发生</td><tr/>
|
||||||
|
<tr><td>CanvasMoved</td><td>移动画布原点时候发生</td><tr/>
|
||||||
|
<tr><td>CanvasScaled</td><td>缩放画布时候发生</td><tr/>
|
||||||
|
<tr><td>OptionConnected</td><td>连接节点选项时候发生</td><tr/>
|
||||||
|
<tr><td>OptionDisConnected</td><td>断开节点选项时候发生</td><tr/>
|
||||||
|
<tr><td>OptionConnecting</td><td>正在连接节点选项时候发生</td><tr/>
|
||||||
|
<tr><td>OptionDisConnecting</td><td>正在断开节点选项时候发生</td><tr/>
|
||||||
|
</table>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="span_property" style="background-color:#0090c9;">Option(Dis)Connected</span>
|
||||||
|
<ul>
|
||||||
|
<li><span style="color:orangered">此事件触发时并不代表当前画布中的节点连线成功</span> 请通过获取事件参数中的<span class="span_property">Status</span>字段进行判断
|
||||||
|
<br/>但是<span class="span_property">STNodeOption.Connected</span>事件是成功后才触发 之所以要这样设计是因为考虑到 对于<span class="span_property">STNodeEditor</span>来说 它需要知道一个连接的状态 即使连接不成功也应当告知前端用户为什么会连接不成功 所以失败和成功都会触发事件</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<hr/>
|
||||||
|
<li>
|
||||||
|
<span class="span_property" style="background-color:#0090c9">Option(Dis)Connecting</span>
|
||||||
|
<ul>
|
||||||
|
<li>此事件是在连接或者断开连接正在发生的时候触发 <span style="color:orangered">可通过事件参数<span class="span_property">Continue</span>来决定是否继续或者停止操作</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h2 class="anchor_point" anchor="i">STNode</h2>
|
||||||
|
<p><span style="color:orangered"><span class="span_property">STNode</span>为抽象类 不可实例化 需要用户自己继承重写</span></p>
|
||||||
|
<p><span class="span_property">STNode</span>有三个比较重要的属性<span class="span_property">InputOptions</span><span class="span_property">OutputOptions</span><span class="span_property">Controls</span></p>
|
||||||
|
<p>若把<span class="span_property">STNodeEditor</span>类比成桌面 那么<span class="span_property">STNode</span>就可以类比成一个窗体 虽然作者在节点中提供了<span class="span_property">Controls</span>集合 但是作者没有提供任何的一个封装好的控件 只提供了一个<span class="span_property">STNodeControl</span>基类 若有需要用户可继承此类绘制自己需要的控件</p>
|
||||||
|
<p><span style="color:orangered">继承<span class="span_property">STNode</span>必须提供空参构造器 否则对节点进行保存后无法还原节点 因为还原过程并非序列化 而是通过反射重新构造对象</span></p>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="j">属性</span>
|
||||||
|
<hr/>
|
||||||
|
<table>
|
||||||
|
<tr style="text-align:center;background-color:#505050;">
|
||||||
|
<td>属性名称</td><td>类型</td><td>描述</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>Owner</td><td>STNodeEditor</td><td>获取当前 Node 所有者</td></tr>
|
||||||
|
<tr><td>IsSelected</td><td>bool</td><td>获取或设置 Node 是否处于被选中状态</td></tr>
|
||||||
|
<tr><td>IsActive</td><td>bool</td><td>获取 Node 是否处于活动状态</td></tr>
|
||||||
|
<tr><td>TitleColor</td><td>Color</td><td>获取或设置标题背景颜色</td></tr>
|
||||||
|
<tr><td>MarkColor</td><td>Color</td><td>获取或设置标记信息背景颜色</td></tr>
|
||||||
|
<tr><td>ForeColor</td><td>Color</td><td>获取或设置当前 Node 前景色</td></tr>
|
||||||
|
<tr><td>BackColor</td><td>Color</td><td>获取或设置当前 Node 背景色</td></tr>
|
||||||
|
<tr><td>Title</td><td>string</td><td>获取或设置 Node 标题</td></tr>
|
||||||
|
<tr><td>Mark</td><td>string</td><td>获取或设置 Node 标记信息</td></tr>
|
||||||
|
<tr><td>MarkLines</td><td>string[]</td><td>获取 Node 标记信息行数据</td></tr>
|
||||||
|
<tr><td>Left</td><td>int</td><td>获取或设置 Node 左边坐标</td></tr>
|
||||||
|
<tr><td>Top</td><td>int</td><td>获取或设置 Node 上边坐标</td></tr>
|
||||||
|
<tr><td>Width</td><td>int</td><td>获取或设置 Node 宽度</td></tr>
|
||||||
|
<tr><td>Height</td><td>int</td><td>获取或设置 Node 高度</td></tr>
|
||||||
|
<tr><td>Right</td><td>int</td><td>获取 Node 右边边坐标</td></tr>
|
||||||
|
<tr><td>Bottom</td><td>int</td><td>获取 Node 下边坐标</td></tr>
|
||||||
|
<tr><td>Rectangle</td><td>Rectangle</td><td>获取 Node 矩形区域</td></tr>
|
||||||
|
<tr><td>TitleRectangle</td><td>Rectangle</td><td>获取 Node 标题矩形区域</td></tr>
|
||||||
|
<tr><td>MarkRectangle</td><td>Rectangle</td><td>获取 Node 标记矩形区域</td></tr>
|
||||||
|
<tr><td>TitleHeight</td><td>int</td><td>获取或设置 Node 标题高度</td></tr>
|
||||||
|
<tr><td>InputOptions</td><td>STNodeOptionCollection</td><td>获取输入选项集合</td></tr>
|
||||||
|
<tr><td>InputOptionsCount</td><td>int</td><td>获取输入选项集合个数</td></tr>
|
||||||
|
<tr><td>OutputOptions</td><td>STNodeOptionCollection</td><td>获取输出选项</td></tr>
|
||||||
|
<tr><td>OutputOptionsCount</td><td>int</td><td>获取输出选项个数</td></tr>
|
||||||
|
<tr><td>Controls</td><td>STNodeControlCollection</td><td>获取 Node 所包含的控件集合</td></tr>
|
||||||
|
<tr><td>ControlsCount</td><td>int</td><td>获取 Node 所包含的控件集合个数</td></tr>
|
||||||
|
<tr><td>Location</td><td>Point</td><td>获取 Node 坐标位置</td></tr>
|
||||||
|
<tr><td>Size</td><td>Size</td><td>获取 Node 大小</td></tr>
|
||||||
|
<tr><td>Font</td><td>Font</td><td>获取或设置 Node 字体</td></tr>
|
||||||
|
<tr><td>LockOption</td><td>bool</td><td>获取或设置是否锁定Option选项 锁定后不在接受连接</td></tr>
|
||||||
|
<tr><td>LockLocation</td><td>bool</td><td>获取或设置是否锁定Node位置 锁定后不可移动</td></tr>
|
||||||
|
<tr><td>ContextMenuStrip</td><td>ContextMenuStrip</td><td>获取或设置当前Node 上下文菜单</td></tr>
|
||||||
|
<tr><td>Tag</td><td>object</td><td>获取或设置用户自定义保存的数据</td></tr>
|
||||||
|
</table>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="span_property" style="background-color:#0090c9;">Lock(Option/Location)</span>
|
||||||
|
<ul>
|
||||||
|
<li><img src="./images/lock.gif"/><br/><span class="span_property">LockOption</span>被设定后左上角会出现一把锁 表示节点内所有选项不再接受连接 但可以与其他节点选项断开连接 <span style="color:orangered">但是其他节点也同为被锁定状态 则无法断开</span>
|
||||||
|
<br/><span class="span_property">LockLocation</span>被设定后右上角会出现一枚图钉 表示节点位置不再接受设置</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<hr/><span class="span_title anchor_point" anchor="k">受保护字段</span>
|
||||||
|
<table>
|
||||||
|
<tr style="text-align:center;background-color:#505050;">
|
||||||
|
<td>属性名称</td><td>类型</td><td>描述</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>m_ctrl_active</td><td>STNodeControl</td><td>当前Node中 活动的控件</td></tr>
|
||||||
|
<tr><td>m_ctrl_hover</td><td>STNodeControl</td><td>当前Node中 悬停的控件</td></tr>
|
||||||
|
</table>
|
||||||
|
<p><span style="color:orangered">在上述属性中除了<span class="span_property">Mark</span><span class="span_property">Left</span><span class="span_property">Top</span>其余均为只读属性 被<span class="span_property">protected</span>所修饰 仅继承<span class="span_property">STNode</span>后才可访问 不然作者觉得太危险了 比如下面这段代码</span></p>
|
||||||
|
<p><span class="span_property">NodeXXX.Owner.Nodes[nIndex].InputOptions.RemoveAt(0);</span></p>
|
||||||
|
<p>节点都是模块化的 可能会有不同的人来做开发 甚至是以插件的方式提供 如果大家都遵守约定那将很好 可如果一旦有人不遵守约定 或者出现意外情况 那么就可能出现跨节点操作 破坏掉原本一个正常的节点 如果确实有需要请更改源代码</p>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="l">可重载函数</span>
|
||||||
|
<table>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当Node被构造时候发生</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnCreate()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当所有者发生改变时候发生</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnOwnerChanged()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当选中状态改变时候发生</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnSelectedChanged()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当活动状态改变时候发生</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnActiveChanged()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">绘制整个Node</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawNode(DrawingTools dt)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">绘制Node标题部分</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawTitle(DrawingTools dt)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">绘制Node主体部分 除去标题部分</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawBody(DrawingTools dt)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">绘制标记信息</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnDrawMark(DrawingTools dt)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </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"> </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>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>op</td><td>指定的选项</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">计算当前Node所需要的矩形区域</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">Size OnBuildNodeSize(DrawingTools dt)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" style="background-color:#343434"><span style="color:orangered">若需要自己重绘Node 则应当重写此函数 以确定绘图区域大小
|
||||||
|
<br/>返回的大小并不会限制绘制区域 任然可以在此区域之外绘制
|
||||||
|
<br/>但是并不会被STNodeEditor所接受 并触发对应事件</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">计算当前Mark所需要的矩形区域</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">Rectangle OnBuildMarkRectangle(DrawingTools dt)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>dt</td><td>绘制工具</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" style="background-color:#343434"><span style="color:orangered">若需要自己重绘Mark 则应当重写此函数 以确定绘图区域大小
|
||||||
|
<br/>返回的大小并不会限制绘制区域 任然可以在此区域之外绘制
|
||||||
|
<br/>但是并不会被STNodeEditor所接受 并触发对应事件</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当需要保存时候 此Node有哪些需要额外保存的数据</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void OnSaveNode(Dictionary<string, byte[]>)</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"><span style="color:orangered">保存时并不会进行序列化 仅自动保存<span class="span_property">Mark</span>属性 还原时候仅重新通过空参数构造器创建此Node
|
||||||
|
<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>
|
||||||
|
<td>dic</td><td>保存时候的数据</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
</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><<span style="color:cornflowerblue">string</span>, <span style="color:cornflowerblue">byte</span>[]>) {
|
||||||
|
dic.Add(<span style="color:lime">"count"</span>, <span style="color:cyan">BitConverter</span>.GetBytes(<span style="color:cornflowerblue">this</span>.InputOptionsCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
<span style="color:cornflowerblue">protected</span> <span style="color:cornflowerblue">internal</span> <span style="color:cornflowerblue">override void </span>OnLoadNode(<span style="color:cyan">Dictionary</span><<span style="color:cornflowerblue">string</span>, <span style="color:cornflowerblue">byte</span>[]> dic) {
|
||||||
|
<span style="color:cornflowerblue">int</span> nCount = <span style="color:cyan">BitConverter</span>.ToInt32(dic[<span style="color:lime">"count"</span>], 0);
|
||||||
|
<span style="color:cornflowerblue">while</span> (<span style="color:cornflowerblue">this</span>.InputOptionsCount < nCount && <span style="color:cornflowerblue">this</span>.InputOptionsCount != nCount)
|
||||||
|
<span style="color:cornflowerblue">this</span>.Addhub();
|
||||||
|
}
|
||||||
|
</pre></div>
|
||||||
|
<p><img style="width:116px;" src="./images/object_type.png"/>
|
||||||
|
<br/>上面代码片段为<span class="span_property">STNodeHub</span>重载 当需要保存时候此节点需要保存当前已拥有的行数 还原的时候需要将行数还原 因为新构造的节点只有一行 若上面已有连线关系的时候只有一行可能无法正常还原连线关系</p>
|
||||||
|
<hr/>
|
||||||
|
<div><pre><span style="color:cornflowerblue">protected override void</span> OnSaveNode(<span style="color:cyan">Dictionary</span><<span style="color:cornflowerblue">string</span>, <span style="color:cornflowerblue">byte</span>[]>) {
|
||||||
|
dic.Add(<span style="color:lime">"file"</span>, <span style="color:cyan">Encoding</span>.UTF8.GetBytes(m_str_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
<span style="color:cornflowerblue">protected</span> <span style="color:cornflowerblue">override void </span>OnLoadNode(<span style="color:cyan">Dictionary</span><<span style="color:cornflowerblue">string</span>, <span style="color:cornflowerblue">byte</span>[]> dic) {
|
||||||
|
m_str_file = <span style="color:cyan">Encoding</span>.UTF8.GetString(dic[<span style="color:lime">"file"</span>]);
|
||||||
|
if (System.IO.<span style="color:cyan">File</span>.Exists(m_str_file)) { <span style="color:lime">//如果文件存在加载并投递数据</span>
|
||||||
|
m_option_out.TransferData(<span style="color:cyan">Image</span>.FromFile(m_str_file));
|
||||||
|
}
|
||||||
|
}</pre></div>
|
||||||
|
<p><img style="width:173px;" src="./images/open_image.png"/>
|
||||||
|
<br/>上面代码片段为DEMO中<span class="span_property">STNodeImageInput</span>重载 因为保存时候 需要把已经打开的文件路劲一起保存 还原的时候再次打开文件并传递数据</p>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="m">其他重载函数</span>
|
||||||
|
<p>
|
||||||
|
<span class="span_property">OnGotFocus</span><span class="span_property">OnLostFocus</span><span class="span_property">OnMouse***</span><span class="span_property">OnKey***</span><span class="span_property">OnMove</span>
|
||||||
|
</p>
|
||||||
|
<span class="span_title anchor_point" anchor="n">公开函数</span>
|
||||||
|
<table>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">重绘Node</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void Invalidate()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">重绘 Node 指定区域</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void Invalidate(Rectangle rect)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>rect</td><td>Node 指定区域</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">获取此Node所包含的输入Option集合</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">STNodeOption[] GetInputOptions()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">获取此Node所包含的输出Option集合</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">STNodeOption[] GetOutputOptions()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">设置Node的选中状态</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void SetSelected(bool bSelected, bool bRedraw)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>bSelected</td><td>是否选中</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>bRedraw</td><td>是否立即重绘</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">此函数参照<span class="span_property">System.Windows.Forms.Control</span></td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">XXX Begin/Invoke(Delegate method, params object[] args)</td></tr>
|
||||||
|
</table>
|
||||||
|
<span class="span_title anchor_point" anchor="o">关于重绘</span>
|
||||||
|
<p><img style="max-width:537px;" src="./images/node.png"/>
|
||||||
|
<br/>若无特殊需求 仅仅需要的是输入输出点就足够了 那么无需用户进行重绘操作 上图 "Demo_Node" 就是默认的绘制 用户只需要在节点中加入需要的输入输出选项即可</p>
|
||||||
|
<div style="overflow:auto;margin:0px 10px;max-width:100%"><pre><span style="color:cornflowerblue">protected</span> <span style="color:cornflowerblue">override</span> <span style="color:cornflowerblue">void</span> OnCreate() {
|
||||||
|
<span style="color:cornflowerblue">base</span>.OnCreate();
|
||||||
|
<span style="color:cornflowerblue">this</span>.InputOptions.Add(<span style="color:cornflowerblue">new</span> STNodeOption(<span style="color:lime">"Input"</span>, <span style="color:cornflowerblue">typeof</span>(<span style="color:cornflowerblue">string</span>), <span style="color:cornflowerblue">false</span>));
|
||||||
|
<span style="color:cornflowerblue">this</span>.InputOptions.Add(<span style="color:cornflowerblue">new</span> STNodeOption(<span style="color:lime">"SingleNode"</span>, <span style="color:cornflowerblue">typeof</span>(<span style="color:cyan">Image</span>), <span style="color:cornflowerblue">true</span>));
|
||||||
|
<span style="color:cornflowerblue">this</span>.InputOptions.Add(<span style="color:cornflowerblue">new</span> STNodeOption(<span style="color:lime">"SingleNode"</span>, <span style="color:cornflowerblue">typeof</span>(<span style="color:cyan">Icon</span>), <span style="color:cornflowerblue">true</span>));
|
||||||
|
|
||||||
|
<span style="color:cornflowerblue">this</span>.OutputOptions.Add(<span style="color:cornflowerblue">new</span> STNodeOption(<span style="color:lime">"output"</span>, <span style="color:cornflowerblue">typeof</span>(<span style="color:cornflowerblue">string</span>), <span style="color:cornflowerblue">false</span>));
|
||||||
|
<span style="color:cornflowerblue">this</span>.OutputOptions.Add(<span style="color:cornflowerblue">new</span> STNodeOption(<span style="color:lime">"Single"</span>, <span style="color:cornflowerblue">typeof</span>(<span style="color:cornflowerblue">string</span>), <span style="color:cornflowerblue">true</span>));
|
||||||
|
<span style="color:cornflowerblue">this</span>.Title = <span style="color:lime">"Demo_Node"</span>;
|
||||||
|
}</pre></div>
|
||||||
|
<p>上面代码片段为 "Demo_Node" 的<span class="span_property">OnCreate</span>重载 加入了三个输入节点和两个输出节点 <span style="color:orangered">(当然上面的代码并没有绑定<span class="span_property">STNodeOption</span>的事件)</span> 若需要自定义绘制参考Demo代码</p>
|
||||||
|
<h2 class="anchor_point" anchor="p">STNodeOption</h2>
|
||||||
|
<p><span class="span_property">STNodeOption</span>为<span class="span_property">STNode</span>下选项的连接点</p>
|
||||||
|
<p style="color:orangered"><span class="span_property">TransferData(object data)</span>是关键函数 当被调用时数据将自动传递到与它相连的所有选项中 并触发目标选项的<span class="span_property">DataTransfer</span>事件
|
||||||
|
<br/>此函数是节点选项之间数据传递的核心</p>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="q">属性</span>
|
||||||
|
<table>
|
||||||
|
<tr style="text-align:center;background-color:#505050;">
|
||||||
|
<td>属性名称</td><td>类型</td><td>描述</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>Owner</td><td>STNode</td><td>获取当前 Option 所属的 Node</td></tr>
|
||||||
|
<tr><td>IsSingle</td><td>bool</td><td>获取当前 Option 是否仅能被连接一次</td></tr>
|
||||||
|
<tr><td>IsInput</td><td>bool</td><td>获取当前 Option 是否是输入选项</td></tr>
|
||||||
|
<tr><td>TextColor</td><td>Color</td><td>获取或设置当前 Option 文本的颜色</td></tr>
|
||||||
|
<tr><td>DotColor</td><td>Color</td><td>获取或设置当前 Option 连接点的颜色</td></tr>
|
||||||
|
<tr><td>Text</td><td>string</td><td>获取或设置当前 Option 显示文本</td></tr>
|
||||||
|
<tr><td>DotLeft</td><td>int</td><td>获取当前 Option 连接点的左边坐标</td></tr>
|
||||||
|
<tr><td>DotTop</td><td>int</td><td>获取当前 Option 连接点的上边坐标</td></tr>
|
||||||
|
<tr><td>DotSize</td><td>int</td><td>获取当前 Option 连接点的宽度</td></tr>
|
||||||
|
<tr><td>Data</td><td>object</td><td>获取或者设置当前 Option 所包含的数据</td></tr>
|
||||||
|
<tr><td>DataType</td><td>Type</td><td>获取当前 Option 数据类型</td></tr>
|
||||||
|
<tr><td>DotRectangle</td><td>Rectangle</td><td>获取当前 Option 连接点的区域</td></tr>
|
||||||
|
<tr><td>ConnectionCount</td><td>int</td><td>获取当前 Option 被连接的个数</td></tr>
|
||||||
|
</table>
|
||||||
|
<span class="span_title anchor_point" anchor="r">受保护字段</span>
|
||||||
|
<table>
|
||||||
|
<tr style="text-align:center;background-color:#505050;">
|
||||||
|
<td>属性名称</td><td>类型</td><td>描述</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>m_hs_connected</td><td>HashSet<STNodeOption></td><td>保存已经被连接的点</td></tr>
|
||||||
|
</table>
|
||||||
|
<p><span style="color:orangered">上述中不带 "设置" 二字的都为只读属性 即便是继承至<span class="span_property">STNodeOption</span></span>
|
||||||
|
<br/>因为作者认为<span class="span_property">STNodeOption</span>最大的用途应该是作为节点之间连线的载体和事件的触发 而对于其他外观需求并不是很重要</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="span_property" style="background-color:#0090c9;">DotColor</span>
|
||||||
|
<ul>
|
||||||
|
<li>若设置此值 则绘制时候以此值为准 否则查询<span class="span_property">STNodeEditor.TypeColor</span>字段进行颜色匹配</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="span_property" style="background-color:#0090c9;">DataType</span>
|
||||||
|
<ul>
|
||||||
|
<li>此选项允许被连接或者输出的数据类型 若类型无法被兼容 无法完成连线
|
||||||
|
<br/><span style="color:orangered">对于输入类型的节点 每个与其参与连接的输出节点的数据类型必须与输入节点的数据类型相同 或者为输入节点数据类型的子类</span>
|
||||||
|
<br/>在使用过程中作者并不建议子类和父类混合使用 对于输入或者输出的数据类型应当统一为子类或者父类 若混合使用将在一定程度上产生歧义 比如父类颜色被设定成红色子类颜色被设定成黄色 那么在UI上会给人一种无法被连接的错觉 应当统一数据类型所对应的颜色
|
||||||
|
<br/><span style="color:orangered">当数据类型为<span class="span_property">object</span>时 则表示可兼容所有数据类型且以 空心 状态绘制</span>
|
||||||
|
<br/><img style="width:116px;" src="./images/object_type.png"/>
|
||||||
|
<br/>上图中的 "HUB" 节点为内置节点 其节点类型为<span class="span_property">STNodeHub</span>默认状态下其输入输出点都为<span class="span_property">object</span>类型 表示可兼容所有类型 且重载了<span class="span_property">ConnectOption(STNodeOption op)</span>与<span class="span_property">CanConnect(STNodeOption op)</span>函数 一旦被接入或者被接入时则会变更为和对应的数据类型进行连接 若连接成功另则会再增加一行类型为<span class="span_property">object</span>的新行
|
||||||
|
<br/><span style="color:orangered;">但是决定输入类型的<span class="span_property">DataType</span>属性被<span class="span_property">internal</span>修饰 所以若你即使继承至<span class="span_property">STNodeOption</span>也无法改写 只能通过构造器传递 因为处于连线状态突然变更类型会带来一系列的问题 即便编辑器发现变更时候可以选择自动断开所有不相符的连接 但是作者并不建议或者打算这么做 若有此需求请更改源代码</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="s">构造器</span>
|
||||||
|
<hr/>
|
||||||
|
<table>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">构造一个 Option</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">STNodeOption(string strText, Type dataType, bool bSingle)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>strText</td><td>显示文本</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>dataType</td><td>数据类型</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>bSingle</td><td>是否为单连接 <span style="color:orangered">若为true则以圆形绘制 否则方形</span></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="t">可重载函数</span>
|
||||||
|
<p><span class="span_property">OnConnected</span><span class="span_property">OnConnecting</span><span class="span_property">OnDisConnected</span><span class="span_property">OnDisConnecting</span><span class="span_property">OnDataTransfer</span></p>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="u">公开函数</span>
|
||||||
|
<hr/>
|
||||||
|
<table>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当前 Option 连接目标 Option</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">virtual ConnectionStatus ConnectOption(STNodeOption op)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>op</td><td>需要连接的 Option</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">检测当前 Option 是否可以连接目标 Option</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">virtual ConnectionStatus CanConnect(STNodeOption op)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>op</td><td>需要连接的 Option</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"><span style="color:orangered">当前Option具备连接目标Option的条件 不代表目标Option也具备连当前Option的条件</span></td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">当前 Option 断开目标 Option</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">virtual bool DisConnection(STNodeOption op)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>op</td><td>需要断开的 Option</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">断开当前 Option 的所有连接</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void DisConnectionAll()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">获取当前 Option 所连接的 Option 集合</td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">List<STNodeOption> GetConnectedOption()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2"><span style="color:orangered">向当前 Option 所连接的所有 Option 投递数据</span></td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void TransferData()</td></tr>
|
||||||
|
<tr><td colspan="2" style="background-color:#343434"> </td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2"><span style="color:orangered">向当前 Option 所连接的所有 Option 投递数据</span></td></tr>
|
||||||
|
<tr style="background-color:#505050"><td colspan="2">void TransferData(object data)</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>data</td><td>需要投递的数据</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr/><span class="span_title anchor_point" anchor="v">事件</span><hr/>
|
||||||
|
<table>
|
||||||
|
<tr><td>Connected</td><td>当被连接时候发生</td><tr/>
|
||||||
|
<tr><td>Connecting</td><td>当连接正在被连接时发生</td><tr/>
|
||||||
|
<tr><td>Disconnected</td><td>当被断开时候发生</td><tr/>
|
||||||
|
<tr><td>DisConnecting</td><td>当连接正在被断开时发生</td><tr/>
|
||||||
|
<tr><td>DataTransfer</td><td>当有数据传递时候发生</td><tr/>
|
||||||
|
</table>
|
||||||
|
<p>当<span class="span_property">Connected</span>与<span class="span_property">DisConnected</span>触发的同时<span class="span_property">DataTransfer</span>也会触发
|
||||||
|
<br/>所以通常情况下<span class="span_property">DataTransfer</span>事件足够使用 通过对事件参数<span class="span_property">Status</span>可得到 当前事件触发时候目标<span class="span_property">Option</span>与当前<span class="span_property">Option</span>的连线关系</p>
|
||||||
|
<p><span style="color:orangered">当一个连线完成或者断开时候 输入和输出<span class="span_property">STNodeOption</span>都将触发事件 因为无论连接还是断开都应该是相对的需要两个节点共同参与 而通常情况下只需要对输入节点进行事件绑定即可</span></p>
|
||||||
|
<h2 class="anchor_point" anchor="w">STNodeOptionEventArgs</h2>
|
||||||
|
<p><span class="span_property">STNodeOptionEventArgs</span>为包含了<span class="span_property">STNodeOption</span>相关事件的事件参数</p>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="x">属性</span>
|
||||||
|
<table>
|
||||||
|
<tr style="text-align:center;background-color:#505050;">
|
||||||
|
<td>属性名称</td><td>类型</td><td>描述</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>TargetOption</td><td>STNodeOption</td><td>触发此事件的对应Option</td></tr>
|
||||||
|
<tr><td>Status</td><td>ConnectionStatus</td><td>Option之间的连线状态</td></tr>
|
||||||
|
<tr><td>IsSponsor</td><td>bool</td><td>是否为此次行为的发起者</td></tr>
|
||||||
|
</table>
|
||||||
|
<hr/>
|
||||||
|
<h2 class="anchor_point" anchor="y">STNodeControl</h2>
|
||||||
|
<p>关于此类不做过多介绍 可将其视为<span class="span_property">System.Windows.Forms.Control</span>虽然提供的属性和事件并没有太多 但是作者认为也应当足够了 若还有其他需求请自行修改源代码</p>
|
||||||
|
<hr/>
|
||||||
|
<span class="span_title anchor_point" anchor="z">Demo</span>
|
||||||
|
<hr/>
|
||||||
|
<div style="overflow:auto;margin:0px 10px;max-width:100%"><pre><span style="color:cornflowerblue">public class</span> <span style="color:cyan">STNodeButton</span> : <span style="color:cyan">STNodeControl</span> //自定义一个Button控件
|
||||||
|
{
|
||||||
|
<span style="color:cornflowerblue">private bool</span> m_isHover;
|
||||||
|
|
||||||
|
<span style="color:cornflowerblue">protected</span> <span style="color:cornflowerblue">override void</span> OnMouseEnter(<span style="color:cyan">EventArgs</span> e) {
|
||||||
|
<span style="color:cornflowerblue">base</span>.OnMouseEnter(e);
|
||||||
|
m_isHover = <span style="color:cornflowerblue">true</span>;
|
||||||
|
<span style="color:cornflowerblue">this</span>.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
<span style="color:cornflowerblue">protected</span> <span style="color:cornflowerblue">override void</span> OnMouseLeave(<span style="color:cyan">EventArgs</span> e) {
|
||||||
|
<span style="color:cornflowerblue">base</span>.OnMouseLeave(e);
|
||||||
|
m_isHover = <span style="color:cornflowerblue">false</span>;
|
||||||
|
<span style="color:cornflowerblue">this</span>.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
<span style="color:cornflowerblue">protected</span> <span style="color:cornflowerblue">override void</span> OnPaint(<span style="color:cyan">DrawingTools</span> dt) {
|
||||||
|
<span style="color:lime">//base.OnPaint(dt);</span>
|
||||||
|
<span style="color:cyan">Graphics</span> g = dt.<span style="color:cyan">Graphics</span>;
|
||||||
|
<span style="color:cyan">SolidBrush</span> brush = dt.<span style="color:cyan">SolidBrush</span>;
|
||||||
|
brush.Color = m_isHover ? <span style="color:cyan">Color</span>.DodgerBlue : <span style="color:cornflowerblue">this</span>.BackColor;
|
||||||
|
g.FillRectangle(brush, 0, 0, <span style="color:cornflowerblue">this</span>.Width, <span style="color:cornflowerblue">this</span>.Height);
|
||||||
|
g.DrawString(<span style="color:cornflowerblue">this</span>.Text, <span style="color:cornflowerblue">this</span>.Font, <span style="color:cyan">Brushes</span>.White, <span style="color:cornflowerblue">this</span>.ClientRectangle, <span style="color:cornflowerblue">base</span>.m_sf);
|
||||||
|
}
|
||||||
|
}</pre></div><div style="overflow:auto;margin:0px 10px;max-width:100%;"><pre><span style="color:cornflowerblue">public</span> <span style="color:cornflowerblue">class</span> <span style="color:cyan">STNodeImageInput</span> : <span style="color:cyan">STNode</span>
|
||||||
|
{
|
||||||
|
<span style="color:cornflowerblue">private</span> <span style="color:cyan">STNodeOption</span> m_option_out;
|
||||||
|
|
||||||
|
<span style="color:cornflowerblue">protected</span> <span style="color:cornflowerblue">override void</span> OnCreate() {
|
||||||
|
<span style="color:cornflowerblue">base</span>.OnCreate();
|
||||||
|
<span style="color:cornflowerblue">this</span>.Title = <span style="color:lime">"ImageInput"</span>;
|
||||||
|
m_option_out = <span style="color:cornflowerblue">new</span> <span style="color:cyan">STNodeOption</span>(<span style="color:lime">""</span>, <span style="color:cornflowerblue">typeof</span>(<span style="color:cyan">Image</span>), <span style="color:cornflowerblue">false</span>);
|
||||||
|
<span style="color:cornflowerblue">this</span>.OutputOptions.Add(m_option_out);
|
||||||
|
<span style="color:cyan">STNodeButton</span> btn = <span style="color:cornflowerblue">new</span> <span style="color:cyan">STNodeButton</span>();
|
||||||
|
btn.Left = 10; btn.Top = 10;
|
||||||
|
btn.Text = <span style="color:lime">"OpenImage"</span>;
|
||||||
|
btn.MouseClick += <span style="color:cornflowerblue">new</span> <span style="color:cyan">MouseEventHandler</span>(btn_MouseClick);
|
||||||
|
<span style="color:cornflowerblue">this</span>.Controls.Add(btn);
|
||||||
|
}
|
||||||
|
<span style="color:lime">//...other code</span>
|
||||||
|
}</pre>
|
||||||
|
</div>
|
||||||
|
<p><img style="width:173px;" src="./images/open_image.png"/>
|
||||||
|
<br/>上面代码片段为 DEMO 中 "ImageInput" 节点与自定义 Button 控件代码 以上代码演示了如何自定义与使用一个控件 可以看到与<span class="span_property">System.Windows.Forms.Control</span>差异并不是很大 多以这里并不做过多介绍</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
Document/grid.png
Executable file
After Width: | Height: | Size: 20 KiB |
BIN
Document/images/channel.png
Executable file
After Width: | Height: | Size: 197 KiB |
BIN
Document/images/form1.png
Executable file
After Width: | Height: | Size: 151 KiB |
BIN
Document/images/formImage.png
Executable file
After Width: | Height: | Size: 204 KiB |
BIN
Document/images/lock.gif
Executable file
After Width: | Height: | Size: 744 KiB |
BIN
Document/images/node.gif
Executable file
After Width: | Height: | Size: 742 KiB |
BIN
Document/images/node.png
Executable file
After Width: | Height: | Size: 64 KiB |
BIN
Document/images/object_type.png
Executable file
After Width: | Height: | Size: 14 KiB |
BIN
Document/images/open_image.png
Executable file
After Width: | Height: | Size: 29 KiB |
79
Document/index.html
Executable file
@ -0,0 +1,79 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<base target="_blank" />
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
|
||||||
|
<title>STNodeEditor</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./css/index.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="div_img_node"><img src="./images/node.png"/><img src="./images/node.gif"/></div>
|
||||||
|
<div id="div_body">
|
||||||
|
<div style="text-align:center">
|
||||||
|
<span class="span_title">STNodeEditor</span><br/>
|
||||||
|
<a class="a_top_btn" href="https://DebugST.github.io/DotNet_WinForm_NodeEditor">项目地址</a><a class="a_top_btn" href="./doc.html">开发文档</a><a class="a_top_btn" href="./ST.Library.UI.dll">类库下载</a>
|
||||||
|
</div>
|
||||||
|
<div style="padding:5px 20px;">
|
||||||
|
<hr/>
|
||||||
|
<p>或许你未曾接触过节点编辑 但节点编辑的影子越来越多 尤其是在影视相关的一些设计类软件当中 Blender,C4D,Houdini,Davinci 等</p>
|
||||||
|
<p style="color:orangered"><span class="span_note">STNodeEditor</span>的使用方式非常简洁 提供了丰富的属性以及事件 可以非常方便的完成节点之间数据的交互及通知 大量的重载函数供开发者使用具有很高的自由性<br/>此控件采用<a class="span_note" href="https://opensource.org/licenses/mit-license.php">MIT</a>开源协议开源 使开发者能够拥有更大的自由度更少的限制</p>
|
||||||
|
<p>节点编辑最大的好处就是可视化操作 将单一的功能点封装到节点之中 让用户通过节点布线来组合自己需要的逻辑 让整个流程可视化 而不是将你程序的整个执行流程固化在你的程序之中 当然在这之前你需要定义好节点的数据类型 <span style="color:orangered">因为数据类型无法兼容是不允许连线的</span> 通常情况下同颜色的连接点表示数据类型相同</p>
|
||||||
|
<p>另一个好处 让开发者只需要注重单一的功能点开发 使得功能与功能之间的耦合度降低 开发者在节点中开发完成需要的功能 无需知道应该把数据交给谁或者怎么去传递数据 只需要将你的结果数据打包给你需要输出的选项点 无论节点间布线多么的复杂 节点编辑器会自动完成数据的投递过程</p>
|
||||||
|
<hr/>
|
||||||
|
<div style="overflow:hidden">
|
||||||
|
<div style="float:left;"><img src="./images/form1.png" width=642></div>
|
||||||
|
<div style="float:left; padding:10px; max-width:322px;">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span>移动画布</span>
|
||||||
|
<ul>
|
||||||
|
<li><span class="span_note">鼠标中键</span>拖动</li>
|
||||||
|
<li>MacBook可使用二指拖动<span class="span_note">触控板</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<br/>
|
||||||
|
<li>
|
||||||
|
<span>缩放画布</span>
|
||||||
|
<ul><li>按下<span class="span_note">Control</span> + <span class="span_note">鼠标滚轮</span></li></ul>
|
||||||
|
</li>
|
||||||
|
<br/>
|
||||||
|
<li>
|
||||||
|
<span>移动节点</span>
|
||||||
|
<ul><li><span class="span_note">鼠标左键</span>按下<span class="span_note">节点标题</span>拖动</li></ul>
|
||||||
|
</li>
|
||||||
|
<br/>
|
||||||
|
<li>
|
||||||
|
<span>删除连线</span>
|
||||||
|
<ul><li>悬停连线 <span class="span_note">鼠标右键</span></li></ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br/>
|
||||||
|
<p style="color:hotpink">方形为多连接选项 圆形为单连接选项</p>
|
||||||
|
<p style="color:hotpink">自定义选项颜色 应当同一颜色为同一数据类型 不同数据类型无法建立连线</p>
|
||||||
|
<p style="color:hotpink">内置<span class="span_note">HUB</span>集线器节点 方便布线</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
<div style="overflow:hidden">
|
||||||
|
<div style="float:left; padding:10px; max-width:322px;">
|
||||||
|
<p style="color:hotpink;">强大的<span class="span_note">UI</span>自定义能力 可快速帮助开发者定义出需要的节点界面</p>
|
||||||
|
<p style="color:hotpink;">提供的<span class="span_note">STNodeControl</span>基类与<span class="span_note">System.Windows.Forms.Control</span>拥有差不多的接口 可使开发者能够像自定义<span class="span_note">WinForm</span>控件一样定义节点的控件</p>
|
||||||
|
<p>即便用户不进行自定义 选项默认将按照一行一行排列</p>
|
||||||
|
<p>基类<span class="span_note">STNode</span>为<span class="span_note">抽象类</span> 不可实例化 需开发者继承向其添加选项 并重载需要的函数进行自定义样式</p>
|
||||||
|
<p>具体细节参考项目中的Demo或查看开发文档</p>
|
||||||
|
</div>
|
||||||
|
<div style="float:left;"><img src="./images/formImage.png" width=642></div>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
<div style="font-size:12px;position:relative;">
|
||||||
|
<table style="color:gray">
|
||||||
|
<tr><td style="width:70px;">.Net版本:</td><td>.Net Framework 3.5</td></tr>
|
||||||
|
<tr><td> VS版本:</td><td>Visual Studio 2010</td></tr>
|
||||||
|
</table>
|
||||||
|
<span style="position:absolute;right:0px;bottom:0px;border:solid 1px black;border-radius:5px;padding:1px 5px;">2021-01-06</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
0
Document/js/doc.js
Executable file
0
Document/js/index.js
Executable file
23
Document/js/jquery-1.10.2.min.js
vendored
Executable file
BIN
Document/line.png
Executable file
After Width: | Height: | Size: 24 KiB |
BIN
Document/mark.png
Executable file
After Width: | Height: | Size: 18 KiB |
BIN
Document/node.png
Executable file
After Width: | Height: | Size: 48 KiB |
BIN
Document/out.png
Executable file
After Width: | Height: | Size: 12 KiB |
BIN
Document/result.png
Executable file
After Width: | Height: | Size: 27 KiB |
38
ST.Library.UI/Properties/AssemblyInfo.cs
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Resources;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("ST.Library.UI")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("None")]
|
||||||
|
[assembly: AssemblyProduct("ST.Library.UI")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © Crystal_lz")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("5a7c4557-5eb1-435a-84d2-49cd67d1ac10")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
|
[assembly: NeutralResourcesLanguageAttribute("zh-Hans")]
|
64
ST.Library.UI/ST.Library.UI.csproj
Executable file
@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{EFFCC270-4999-4077-A543-56CCCCE92147}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>ST.Library.UI</RootNamespace>
|
||||||
|
<AssemblyName>ST.Library.UI</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<DocumentationFile>bin\Release\ST.Library.UI.XML</DocumentationFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="STNodeEditor\STNode.cs" />
|
||||||
|
<Compile Include="STNodeEditor\STNodeCollection.cs" />
|
||||||
|
<Compile Include="STNodeEditor\STNodeControl.cs" />
|
||||||
|
<Compile Include="STNodeEditor\STNodeControlCollection.cs" />
|
||||||
|
<Compile Include="STNodeEditor\STNodeEditor.cs">
|
||||||
|
<SubType>Component</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="STNodeEditor\STNodeEditorDataType.cs" />
|
||||||
|
<Compile Include="STNodeEditor\STNodeHub.cs" />
|
||||||
|
<Compile Include="STNodeEditor\STNodeOption.cs" />
|
||||||
|
<Compile Include="STNodeEditor\STNodeOptionCollection.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
874
ST.Library.UI/STNodeEditor/STNode.cs
Executable file
@ -0,0 +1,874 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public abstract class STNode
|
||||||
|
{
|
||||||
|
private STNodeEditor _Owner;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Node 所有者
|
||||||
|
/// </summary>
|
||||||
|
public STNodeEditor Owner {
|
||||||
|
get { return _Owner; }
|
||||||
|
internal set {
|
||||||
|
if (value == _Owner) return;
|
||||||
|
if (_Owner != null) {
|
||||||
|
foreach (STNodeOption op in this._InputOptions) op.DisConnectionAll();
|
||||||
|
foreach (STNodeOption op in this._OutputOptions) op.DisConnectionAll();
|
||||||
|
}
|
||||||
|
_Owner = value;
|
||||||
|
this.OnOwnerChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _IsSelected;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置 Node 是否处于被选中状态
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSelected {
|
||||||
|
get { return _IsSelected; }
|
||||||
|
set {
|
||||||
|
if (value == _IsSelected) return;
|
||||||
|
_IsSelected = value;
|
||||||
|
this.Invalidate();
|
||||||
|
this.OnSelectedChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _IsActive;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 是否处于活动状态
|
||||||
|
/// </summary>
|
||||||
|
public bool IsActive {
|
||||||
|
get { return _IsActive; }
|
||||||
|
internal set {
|
||||||
|
if (value == _IsActive) return;
|
||||||
|
_IsActive = value;
|
||||||
|
this.OnActiveChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _TitleColor;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置标题背景颜色
|
||||||
|
/// </summary>
|
||||||
|
public Color TitleColor {
|
||||||
|
get { return _TitleColor; }
|
||||||
|
protected set {
|
||||||
|
_TitleColor = value;
|
||||||
|
this.Invalidate(this.TitleRectangle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _MarkColor;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置标记信息背景颜色
|
||||||
|
/// </summary>
|
||||||
|
public Color MarkColor {
|
||||||
|
get { return _MarkColor; }
|
||||||
|
protected set {
|
||||||
|
_MarkColor = value;
|
||||||
|
this.Invalidate(this._MarkRectangle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _ForeColor = Color.White;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置当前 Node 前景色
|
||||||
|
/// </summary>
|
||||||
|
public Color ForeColor {
|
||||||
|
get { return _ForeColor; }
|
||||||
|
protected set {
|
||||||
|
_ForeColor = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _BackColor;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置当前 Node 背景色
|
||||||
|
/// </summary>
|
||||||
|
public Color BackColor {
|
||||||
|
get { return _BackColor; }
|
||||||
|
protected set {
|
||||||
|
_BackColor = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _Title;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置 Node 标题
|
||||||
|
/// </summary>
|
||||||
|
public string Title {
|
||||||
|
get { return _Title; }
|
||||||
|
protected set {
|
||||||
|
_Title = value;
|
||||||
|
this.Invalidate(this.TitleRectangle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _Mark;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置 Node 标记信息
|
||||||
|
/// </summary>
|
||||||
|
public string Mark {
|
||||||
|
get { return _Mark; }
|
||||||
|
set {
|
||||||
|
_Mark = value;
|
||||||
|
if (value == null)
|
||||||
|
_MarkLines = null;
|
||||||
|
else
|
||||||
|
_MarkLines = (from s in value.Split('\n') select s.Trim()).ToArray();
|
||||||
|
this.BuildSize(false, true, true);
|
||||||
|
//if (this._Owner != null) this._Owner.Invalidate();
|
||||||
|
//this.Invalidate();
|
||||||
|
//this.Invalidate(this._MarkRectangle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string[] _MarkLines;//单独存放行数据 不用每次在绘制中去拆分
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 标记信息行数据
|
||||||
|
/// </summary>
|
||||||
|
public string[] MarkLines {
|
||||||
|
get { return _MarkLines; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Left;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置 Node 左边坐标
|
||||||
|
/// </summary>
|
||||||
|
public int Left {
|
||||||
|
get { return _Left; }
|
||||||
|
set {
|
||||||
|
if (this._LockLocation) return;
|
||||||
|
_Left = value;
|
||||||
|
this.BuildSize(false, true, false);
|
||||||
|
//this._MarkRectangle = this.OnBuildMarkRectangle();
|
||||||
|
if (this._Owner != null) {
|
||||||
|
this._Owner.BuildLinePath();
|
||||||
|
this._Owner.BuildBounds();
|
||||||
|
}
|
||||||
|
this.OnMove(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Top;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置 Node 上边坐标
|
||||||
|
/// </summary>
|
||||||
|
public int Top {
|
||||||
|
get { return _Top; }
|
||||||
|
set {
|
||||||
|
if (this._LockLocation) return;
|
||||||
|
_Top = value;
|
||||||
|
this.BuildSize(false, true, false);
|
||||||
|
//this._MarkRectangle = this.OnBuildMarkRectangle();
|
||||||
|
if (this._Owner != null) {
|
||||||
|
this._Owner.BuildLinePath();
|
||||||
|
this._Owner.BuildBounds();
|
||||||
|
}
|
||||||
|
this.OnMove(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Width;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置 Node 宽度
|
||||||
|
/// </summary>
|
||||||
|
public int Width {
|
||||||
|
get { return _Width; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Height;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置 Node 高度
|
||||||
|
/// </summary>
|
||||||
|
public int Height {
|
||||||
|
get { return _Height; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 右边边坐标
|
||||||
|
/// </summary>
|
||||||
|
public int Right {
|
||||||
|
get { return _Left + _Width; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 下边坐标
|
||||||
|
/// </summary>
|
||||||
|
public int Bottom {
|
||||||
|
get { return _Top + _Height; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 矩形区域
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle Rectangle {
|
||||||
|
get {
|
||||||
|
return new Rectangle(this._Left, this._Top, this._Width, this._Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 标题矩形区域
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle TitleRectangle {
|
||||||
|
get {
|
||||||
|
return new Rectangle(this._Left, this._Top, this._Width, this._TitleHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle _MarkRectangle;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 标记矩形区域
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle MarkRectangle {
|
||||||
|
get { return _MarkRectangle; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _TitleHeight = 20;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置 Node 标题高度
|
||||||
|
/// </summary>
|
||||||
|
public int TitleHeight {
|
||||||
|
get { return _TitleHeight; }
|
||||||
|
protected set { _TitleHeight = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private STNodeOptionCollection _InputOptions;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取输入选项集合
|
||||||
|
/// </summary>
|
||||||
|
protected internal STNodeOptionCollection InputOptions {
|
||||||
|
get { return _InputOptions; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取输入选项集合个数
|
||||||
|
/// </summary>
|
||||||
|
public int InputOptionsCount { get { return _InputOptions.Count; } }
|
||||||
|
|
||||||
|
private STNodeOptionCollection _OutputOptions;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取输出选项
|
||||||
|
/// </summary>
|
||||||
|
protected internal STNodeOptionCollection OutputOptions {
|
||||||
|
get { return _OutputOptions; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取输出选项个数
|
||||||
|
/// </summary>
|
||||||
|
public int OutputOptionsCount { get { return _OutputOptions.Count; } }
|
||||||
|
|
||||||
|
private STNodeControlCollection _Controls;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 所包含的控件集合
|
||||||
|
/// </summary>
|
||||||
|
protected STNodeControlCollection Controls {
|
||||||
|
get { return _Controls; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 所包含的控件集合个数
|
||||||
|
/// </summary>
|
||||||
|
public int ControlsCount { get { return _Controls.Count; } }
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 坐标位置
|
||||||
|
/// </summary>
|
||||||
|
public Point Location { get { return new Point(this._Left, this._Top); } }
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Node 大小
|
||||||
|
/// </summary>
|
||||||
|
public Size Size { get { return new Size(this._Width, this._Height); } }
|
||||||
|
|
||||||
|
private Font _Font;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置 Node 字体
|
||||||
|
/// </summary>
|
||||||
|
protected Font Font {
|
||||||
|
get { return _Font; }
|
||||||
|
set {
|
||||||
|
if (value == _Font) return;
|
||||||
|
this._Font.Dispose();
|
||||||
|
_Font = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _LockOption;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置是否锁定Option选项 锁定后不在接受连接
|
||||||
|
/// </summary>
|
||||||
|
public bool LockOption {
|
||||||
|
get { return _LockOption; }
|
||||||
|
set {
|
||||||
|
_LockOption = value;
|
||||||
|
this.Invalidate(new Rectangle(0, 0, this._Width, this._TitleHeight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _LockLocation;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置是否锁定Node位置 锁定后不可移动
|
||||||
|
/// </summary>
|
||||||
|
public bool LockLocation {
|
||||||
|
get { return _LockLocation; }
|
||||||
|
set {
|
||||||
|
_LockLocation = value;
|
||||||
|
this.Invalidate(new Rectangle(0, 0, this._Width, this._TitleHeight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ContextMenuStrip _ContextMenuStrip;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置当前Node 上下文菜单
|
||||||
|
/// </summary>
|
||||||
|
public ContextMenuStrip ContextMenuStrip {
|
||||||
|
get { return _ContextMenuStrip; }
|
||||||
|
set { _ContextMenuStrip = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private object _Tag;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置用户自定义保存的数据
|
||||||
|
/// </summary>
|
||||||
|
public object Tag {
|
||||||
|
get { return _Tag; }
|
||||||
|
set { _Tag = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool m_isBuildNodeSize;
|
||||||
|
private bool m_isBuildMarkSize;
|
||||||
|
private static Point m_static_pt_init = new Point(10, 10);
|
||||||
|
|
||||||
|
public STNode(/*string strTitle, int x, int y*/) {
|
||||||
|
//this._Title = strTitle;
|
||||||
|
this._Title = "Untitled";
|
||||||
|
this._Height = this._TitleHeight;
|
||||||
|
this._MarkRectangle.Height = this._Height;
|
||||||
|
this._Left = this._MarkRectangle.X = m_static_pt_init.X;
|
||||||
|
this._Top = m_static_pt_init.Y;
|
||||||
|
this._MarkRectangle.Y = this._Top - 30;
|
||||||
|
this._InputOptions = new STNodeOptionCollection(this, true);
|
||||||
|
this._OutputOptions = new STNodeOptionCollection(this, false);
|
||||||
|
this._Controls = new STNodeControlCollection(this);
|
||||||
|
this._BackColor = Color.FromArgb(200, 64, 64, 64);
|
||||||
|
this._TitleColor = Color.FromArgb(200, Color.DodgerBlue);
|
||||||
|
this._MarkColor = Color.FromArgb(200, Color.Brown);
|
||||||
|
this._Font = new Font("courier new", 8.25f);
|
||||||
|
|
||||||
|
m_sf = new StringFormat();
|
||||||
|
m_sf.Alignment = StringAlignment.Near;
|
||||||
|
m_sf.LineAlignment = StringAlignment.Center;
|
||||||
|
m_sf.FormatFlags = StringFormatFlags.NoWrap;
|
||||||
|
m_sf.SetTabStops(0, new float[] { 40 });
|
||||||
|
m_static_pt_init.X += 10;
|
||||||
|
m_static_pt_init.Y += 10;
|
||||||
|
this.OnCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int m_nItemHeight = 20;
|
||||||
|
protected StringFormat m_sf;
|
||||||
|
/// <summary>
|
||||||
|
/// 当前Node中 活动的控件
|
||||||
|
/// </summary>
|
||||||
|
protected STNodeControl m_ctrl_active;
|
||||||
|
/// <summary>
|
||||||
|
/// 当前Node中 悬停的控件
|
||||||
|
/// </summary>
|
||||||
|
protected STNodeControl m_ctrl_hover;
|
||||||
|
|
||||||
|
public void BuildSize(bool bBuildNode, bool bBuildMark, bool bRedraw) {
|
||||||
|
m_isBuildNodeSize = bBuildNode;
|
||||||
|
m_isBuildMarkSize = bBuildMark;
|
||||||
|
if (bRedraw) {
|
||||||
|
if (this._Owner != null) this._Owner.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void CheckSize(DrawingTools dt) {
|
||||||
|
if (m_isBuildNodeSize) {
|
||||||
|
Size sz = this.OnBuildNodeSize(dt);
|
||||||
|
this._Width = sz.Width;
|
||||||
|
this._Height = sz.Height;
|
||||||
|
m_isBuildNodeSize = false;
|
||||||
|
}
|
||||||
|
if (m_isBuildMarkSize) {
|
||||||
|
m_isBuildMarkSize = true;
|
||||||
|
if (string.IsNullOrEmpty(this._Mark)) return;
|
||||||
|
this._MarkRectangle = this.OnBuildMarkRectangle(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Dictionary<string, byte[]> OnSaveNode() {
|
||||||
|
Dictionary<string, byte[]> dic = new Dictionary<string, byte[]>();
|
||||||
|
dic.Add("Left", BitConverter.GetBytes(this._Left));
|
||||||
|
dic.Add("Top", BitConverter.GetBytes(this._Top));
|
||||||
|
dic.Add("Mark", string.IsNullOrEmpty(this._Mark) ? new byte[] { 0 } : Encoding.UTF8.GetBytes(this._Mark));
|
||||||
|
dic.Add("LockOption", new byte[] { (byte)(this._LockLocation ? 1 : 0) });
|
||||||
|
dic.Add("LockLocation", new byte[] { (byte)(this._LockLocation ? 1 : 0) });
|
||||||
|
this.OnSaveNode(dic);
|
||||||
|
return dic;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal virtual byte[] GetSaveData() {
|
||||||
|
List<byte> lst = new List<byte>();
|
||||||
|
byte[] byData = Encoding.UTF8.GetBytes(this.GetType().GUID.ToString());
|
||||||
|
lst.Add((byte)byData.Length);
|
||||||
|
lst.AddRange(byData);
|
||||||
|
|
||||||
|
var dic = this.OnSaveNode();
|
||||||
|
if (dic != null) {
|
||||||
|
foreach (var v in dic) {
|
||||||
|
byData = Encoding.UTF8.GetBytes(v.Key);
|
||||||
|
lst.AddRange(BitConverter.GetBytes(byData.Length));
|
||||||
|
lst.AddRange(byData);
|
||||||
|
lst.AddRange(BitConverter.GetBytes(v.Value.Length));
|
||||||
|
lst.AddRange(v.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lst.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
//internal virtual byte[] GetSaveData() {
|
||||||
|
// List<byte> lst = new List<byte>();
|
||||||
|
// Type t = this.GetType();
|
||||||
|
// //lst.AddRange(BitConverter.GetBytes(this._Left));
|
||||||
|
// //lst.AddRange(BitConverter.GetBytes(this._Top));
|
||||||
|
// byte[] byData = Encoding.UTF8.GetBytes(t.Module.Name);
|
||||||
|
// lst.Add((byte)byData.Length);
|
||||||
|
// lst.AddRange(byData);
|
||||||
|
// byData = Encoding.UTF8.GetBytes(t.FullName);
|
||||||
|
// lst.Add((byte)byData.Length);
|
||||||
|
// lst.AddRange(byData);
|
||||||
|
|
||||||
|
// //if (!string.IsNullOrEmpty(this._Mark)) {
|
||||||
|
// // byData = Encoding.UTF8.GetBytes(this._Mark);
|
||||||
|
// // lst.AddRange(BitConverter.GetBytes(byData.Length));
|
||||||
|
// // lst.AddRange(byData);
|
||||||
|
// //} else lst.AddRange(new byte[] { 0, 0, 0, 0 });
|
||||||
|
// var dic = this.OnSaveNode();
|
||||||
|
// if (dic != null) {
|
||||||
|
// foreach (var v in dic) {
|
||||||
|
// byData = Encoding.UTF8.GetBytes(v.Key);
|
||||||
|
// lst.AddRange(BitConverter.GetBytes(byData.Length));
|
||||||
|
// lst.AddRange(byData);
|
||||||
|
// lst.AddRange(BitConverter.GetBytes(v.Value.Length));
|
||||||
|
// lst.AddRange(v.Value);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return lst.ToArray();
|
||||||
|
//}
|
||||||
|
|
||||||
|
#region protected
|
||||||
|
/// <summary>
|
||||||
|
/// 当Node被构造时候发生
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnCreate() { }
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制整个Node
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dt">绘制工具</param>
|
||||||
|
protected internal virtual void OnDrawNode(DrawingTools dt) {
|
||||||
|
dt.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
|
||||||
|
//Fill background
|
||||||
|
if (this._BackColor.A != 0) {
|
||||||
|
dt.SolidBrush.Color = this._BackColor;
|
||||||
|
dt.Graphics.FillRectangle(dt.SolidBrush, this._Left, this._Top + this._TitleHeight, this._Width, this.Height - this._TitleHeight);
|
||||||
|
}
|
||||||
|
this.OnDrawTitle(dt);
|
||||||
|
this.OnDrawBody(dt);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制Node标题部分
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dt">绘制工具</param>
|
||||||
|
protected virtual void OnDrawTitle(DrawingTools dt) {
|
||||||
|
m_sf.Alignment = StringAlignment.Center;
|
||||||
|
m_sf.LineAlignment = StringAlignment.Center;
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
SolidBrush brush = dt.SolidBrush;
|
||||||
|
if (this._TitleColor.A != 0) {
|
||||||
|
brush.Color = this._TitleColor;
|
||||||
|
g.FillRectangle(brush, this.TitleRectangle);
|
||||||
|
}
|
||||||
|
if (this._LockOption) {
|
||||||
|
dt.Pen.Color = this.ForeColor;
|
||||||
|
int n = this._Top + this._TitleHeight / 2 - 5;
|
||||||
|
g.DrawRectangle(dt.Pen, this._Left + 3, n + 0, 6, 3);
|
||||||
|
g.DrawRectangle(dt.Pen, this._Left + 2, n + 3, 8, 6);
|
||||||
|
g.DrawLine(dt.Pen, this._Left + 6, n + 5, this._Left + 6, n + 7);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (this._LockLocation) {
|
||||||
|
dt.Pen.Color = this.ForeColor;
|
||||||
|
brush.Color = this._ForeColor;
|
||||||
|
int n = this._Top + this._TitleHeight / 2 - 5;
|
||||||
|
g.FillRectangle(brush, this.Right - 9, n, 5, 7);
|
||||||
|
g.DrawLine(dt.Pen, this.Right - 10, n, this.Right - 4, n);
|
||||||
|
g.DrawLine(dt.Pen, this.Right - 11, n + 6, this.Right - 3, n + 6);
|
||||||
|
g.DrawLine(dt.Pen, this.Right - 7, n + 7, this.Right - 7, n + 9);
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(this._Title) && this._ForeColor.A != 0) {
|
||||||
|
brush.Color = this._ForeColor;
|
||||||
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
|
||||||
|
g.DrawString(this._Title, this._Font, brush, this.TitleRectangle, m_sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制Node主体部分 除去标题部分
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dt">绘制工具</param>
|
||||||
|
protected virtual void OnDrawBody(DrawingTools dt) {
|
||||||
|
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) {
|
||||||
|
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);
|
||||||
|
rect.Y += m_nItemHeight;
|
||||||
|
}
|
||||||
|
rect.Y = this._Top + this._TitleHeight;
|
||||||
|
m_sf.Alignment = StringAlignment.Far;
|
||||||
|
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);
|
||||||
|
rect.Y += m_nItemHeight;
|
||||||
|
}
|
||||||
|
if (this._Controls.Count != 0) { //绘制子控件
|
||||||
|
//将坐标原点与节点对齐
|
||||||
|
dt.Graphics.TranslateTransform(this._Left, this._Top + this._TitleHeight);
|
||||||
|
Point pt = Point.Empty; //当前需要偏移的量
|
||||||
|
Point pt_last = Point.Empty; //最后一个控件相对于节点的坐标
|
||||||
|
foreach (STNodeControl v in this._Controls) {
|
||||||
|
pt.X = v.Left - pt.X;
|
||||||
|
pt.Y = v.Top - pt.Y;
|
||||||
|
pt_last = v.Location;
|
||||||
|
dt.Graphics.TranslateTransform(pt.X, pt.Y); //将原点坐标移动至控件位置
|
||||||
|
v.OnPaint(dt);
|
||||||
|
}
|
||||||
|
//dt.Graphics.TranslateTransform(-pt_last.X, -pt_last.Y); 还原坐标
|
||||||
|
dt.Graphics.TranslateTransform(-this._Left - pt_last.X, -this._Top - this._TitleHeight - pt_last.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制标记信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dt">绘制工具</param>
|
||||||
|
protected internal virtual void OnDrawMark(DrawingTools dt) {
|
||||||
|
if (string.IsNullOrEmpty(this._Mark)) return;
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
SolidBrush brush = dt.SolidBrush;
|
||||||
|
m_sf.LineAlignment = StringAlignment.Center;
|
||||||
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
|
||||||
|
brush.Color = this._MarkColor;
|
||||||
|
g.FillRectangle(brush, this._MarkRectangle); //填充背景色
|
||||||
|
|
||||||
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; //确定文本绘制所需大小
|
||||||
|
var sz = g.MeasureString(this.Mark, this.Font, this._MarkRectangle.Width);
|
||||||
|
brush.Color = this._ForeColor;
|
||||||
|
if (sz.Height > m_nItemHeight || sz.Width > this._MarkRectangle.Width) { //如果超过绘图区 则绘制部分
|
||||||
|
Rectangle rect = new Rectangle(this._MarkRectangle.Left + 2, this._MarkRectangle.Top + 2, this._MarkRectangle.Width - 20, 16);
|
||||||
|
m_sf.Alignment = StringAlignment.Near;
|
||||||
|
g.DrawString(this._MarkLines[0], this._Font, brush, rect, m_sf);
|
||||||
|
m_sf.Alignment = StringAlignment.Far;
|
||||||
|
rect.Width = this._MarkRectangle.Width - 5;
|
||||||
|
g.DrawString("+", this._Font, brush, rect, m_sf); // + 表示超过绘图区
|
||||||
|
} else {
|
||||||
|
m_sf.Alignment = StringAlignment.Near;
|
||||||
|
g.DrawString(this._MarkLines[0].Trim(), this._Font, brush, this._MarkRectangle, m_sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制选项连线的点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dt">绘制工具</param>
|
||||||
|
/// <param name="op">指定的选项</param>
|
||||||
|
protected virtual void OnDrawOptionDot(DrawingTools dt, STNodeOption op) {
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
Pen pen = dt.Pen;
|
||||||
|
SolidBrush brush = dt.SolidBrush;
|
||||||
|
var t = typeof(object);
|
||||||
|
if (op.DotColor != Color.Transparent) //设置颜色
|
||||||
|
brush.Color = op.DotColor;
|
||||||
|
else {
|
||||||
|
if (op.DataType == t)
|
||||||
|
pen.Color = this.Owner.UnknownTypeColor;
|
||||||
|
else
|
||||||
|
brush.Color = this.Owner.TypeColor.ContainsKey(op.DataType) ? this.Owner.TypeColor[op.DataType] : this.Owner.UnknownTypeColor;
|
||||||
|
}
|
||||||
|
if (op.IsSingle) { //单连接 圆形
|
||||||
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
|
||||||
|
if (op.DataType == t) { //未知类型绘制 否则填充
|
||||||
|
g.DrawEllipse(pen, op.DotRectangle.X, op.DotRectangle.Y, op.DotRectangle.Width - 1, op.DotRectangle.Height - 1);
|
||||||
|
} else
|
||||||
|
g.FillEllipse(brush, op.DotRectangle);
|
||||||
|
} else { //多连接 矩形
|
||||||
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
|
||||||
|
if (op.DataType == t) {
|
||||||
|
g.DrawRectangle(pen, op.DotRectangle.X, op.DotRectangle.Y, op.DotRectangle.Width - 1, op.DotRectangle.Height - 1);
|
||||||
|
} else
|
||||||
|
g.FillRectangle(brush, op.DotRectangle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 当计算Option位置时候发生
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="op">需要计算的Option</param>
|
||||||
|
/// <returns>新的位置</returns>
|
||||||
|
protected virtual Point OnSetOptionLocation(STNodeOption op) {
|
||||||
|
return new Point(op.DotLeft, op.DotTop);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 计算当前Node所需要的矩形区域
|
||||||
|
/// 若需要自己重绘Node 则应当重写此函数 以确定绘图区域大小
|
||||||
|
/// 返回的大小并不会限制绘制区域 任然可以在此区域之外绘制
|
||||||
|
/// 但是并不会被STNodeEditor所接受 并触发对应事件
|
||||||
|
/// </summary>
|
||||||
|
protected virtual Size OnBuildNodeSize(DrawingTools dt) {
|
||||||
|
int nInputHeight = 0, nOutputHeight = 0;
|
||||||
|
foreach (STNodeOption op in this._InputOptions) nInputHeight += m_nItemHeight;
|
||||||
|
foreach (STNodeOption op in this._OutputOptions) nOutputHeight += m_nItemHeight;
|
||||||
|
int nHeight = this._TitleHeight + (nInputHeight > nOutputHeight ? nInputHeight : nOutputHeight);
|
||||||
|
|
||||||
|
SizeF szf_input = SizeF.Empty, szf_output = SizeF.Empty;
|
||||||
|
foreach (STNodeOption v in this._InputOptions) {
|
||||||
|
if (string.IsNullOrEmpty(v.Text)) continue;
|
||||||
|
SizeF szf = dt.Graphics.MeasureString(v.Text, this._Font);
|
||||||
|
if (szf.Width > szf_input.Width) szf_input = szf;
|
||||||
|
}
|
||||||
|
foreach (STNodeOption v in this._OutputOptions) {
|
||||||
|
if (string.IsNullOrEmpty(v.Text)) continue;
|
||||||
|
SizeF szf = dt.Graphics.MeasureString(v.Text, this._Font);
|
||||||
|
if (szf.Width > szf_output.Width) szf_output = szf;
|
||||||
|
}
|
||||||
|
int nWidth = (int)(szf_input.Width + szf_output.Width + 25);
|
||||||
|
if (!string.IsNullOrEmpty(this.Title)) szf_input = dt.Graphics.MeasureString(this.Title, this.Font);
|
||||||
|
if (szf_input.Width + 30 > nWidth) nWidth = (int)szf_input.Width + 30;
|
||||||
|
return new Size(nWidth, nHeight);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 计算当前Mark所需要的矩形区域
|
||||||
|
/// 若需要自己重绘Mark 则应当重写此函数 以确定绘图区域大小
|
||||||
|
/// 返回的大小并不会限制绘制区域 任然可以在此区域之外绘制
|
||||||
|
/// 但是并不会被STNodeEditor所接受 并触发对应事件
|
||||||
|
/// </summary>
|
||||||
|
protected virtual Rectangle OnBuildMarkRectangle(DrawingTools dt) {
|
||||||
|
//if (string.IsNullOrEmpty(this._Mark)) return Rectangle.Empty;
|
||||||
|
return new Rectangle(this._Left, this._Top - 30, this._Width, 20);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 当需要保存时候 此Node有哪些需要额外保存的数据
|
||||||
|
/// 注意: 保存时并不会进行序列化 还原时候仅重新通过空参数构造器创建此Node
|
||||||
|
/// 然后调用 OnLoadNode() 将保存的数据进行还原
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dic">需要保存的数据</param>
|
||||||
|
protected virtual void OnSaveNode(Dictionary<string, byte[]> dic) { }
|
||||||
|
/// <summary>
|
||||||
|
/// 当还原该节点时候会将 OnSaveNode() 所返回的数据重新传入此函数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dic">保存时候的数据</param>
|
||||||
|
protected internal virtual void OnLoadNode(Dictionary<string, byte[]> dic) {
|
||||||
|
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("Mark")) {
|
||||||
|
string strText = Encoding.UTF8.GetString(dic["Mark"]);
|
||||||
|
if (strText != "\0") this.Mark = strText;
|
||||||
|
}
|
||||||
|
if (dic.ContainsKey("LockOption")) this._LockOption = dic["LockOption"][0] == 1;
|
||||||
|
if (dic.ContainsKey("LockLocation")) this._LockLocation = dic["LockLocation"][0] == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//[event]===========================[event]==============================[event]============================[event]
|
||||||
|
|
||||||
|
protected internal virtual void OnGotFocus(EventArgs e) { }
|
||||||
|
|
||||||
|
protected internal virtual void OnLostFocus(EventArgs e) { }
|
||||||
|
|
||||||
|
protected internal virtual void OnMouseEnter(EventArgs e) { }
|
||||||
|
|
||||||
|
protected internal virtual void OnMouseDown(MouseEventArgs e) {
|
||||||
|
Point pt = e.Location;
|
||||||
|
pt.Y -= this._TitleHeight;
|
||||||
|
for (int i = this._Controls.Count - 1; i >= 0; i--) {
|
||||||
|
var c = this._Controls[i];
|
||||||
|
if (c.DisplayRectangle.Contains(pt)) {
|
||||||
|
c.OnMouseDown(new MouseEventArgs(e.Button, e.Clicks, e.X - c.Left, pt.Y - c.Top, e.Delta));
|
||||||
|
if (m_ctrl_active != c) {
|
||||||
|
c.OnGotFocus(new EventArgs());
|
||||||
|
if (m_ctrl_active != null) m_ctrl_active.OnLostFocus(new EventArgs());
|
||||||
|
m_ctrl_active = c;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_ctrl_active != null) m_ctrl_active.OnLostFocus(new EventArgs());
|
||||||
|
m_ctrl_active = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnMouseMove(MouseEventArgs e) {
|
||||||
|
Point pt = e.Location;
|
||||||
|
pt.Y -= this._TitleHeight;
|
||||||
|
for (int i = this._Controls.Count - 1; i >= 0; i--) {
|
||||||
|
var c = this._Controls[i];
|
||||||
|
if (c.DisplayRectangle.Contains(pt)) {
|
||||||
|
if (m_ctrl_hover != this._Controls[i]) {
|
||||||
|
c.OnMouseEnter(new EventArgs());
|
||||||
|
if (m_ctrl_hover != null) m_ctrl_hover.OnMouseLeave(new EventArgs());
|
||||||
|
m_ctrl_hover = c;
|
||||||
|
}
|
||||||
|
m_ctrl_hover.OnMouseMove(new MouseEventArgs(e.Button, e.Clicks, e.X - c.Left, pt.Y - c.Top, e.Delta));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_ctrl_hover != null) m_ctrl_hover.OnMouseLeave(new EventArgs());
|
||||||
|
m_ctrl_hover = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnMouseUp(MouseEventArgs e) {
|
||||||
|
Point pt = e.Location;
|
||||||
|
pt.Y -= this._TitleHeight;
|
||||||
|
if (m_ctrl_active != null) {
|
||||||
|
m_ctrl_active.OnMouseUp(new MouseEventArgs(e.Button, e.Clicks,
|
||||||
|
e.X - m_ctrl_active.Left, pt.Y - m_ctrl_active.Top, e.Delta));
|
||||||
|
}
|
||||||
|
//for (int i = this._Controls.Count - 1; i >= 0; i--) {
|
||||||
|
// var c = this._Controls[i];
|
||||||
|
// if (c.DisplayRectangle.Contains(pt)) {
|
||||||
|
// c.OnMouseUp(new MouseEventArgs(e.Button, e.Clicks, e.X - c.Left, pt.Y - c.Top, e.Delta));
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnMouseLeave(EventArgs e) {
|
||||||
|
if (m_ctrl_hover != null) m_ctrl_hover.OnMouseLeave(e);
|
||||||
|
m_ctrl_hover = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnMouseClick(MouseEventArgs e) {
|
||||||
|
Point pt = e.Location;
|
||||||
|
pt.Y -= this._TitleHeight;
|
||||||
|
if (m_ctrl_active != null)
|
||||||
|
m_ctrl_active.OnMouseClick(new MouseEventArgs(e.Button, e.Clicks, e.X - m_ctrl_active.Left, pt.Y - m_ctrl_active.Top, e.Delta));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnMouseWheel(MouseEventArgs e) {
|
||||||
|
Point pt = e.Location;
|
||||||
|
pt.Y -= this._TitleHeight;
|
||||||
|
if (m_ctrl_hover != null) {
|
||||||
|
m_ctrl_hover.OnMouseWheel(new MouseEventArgs(e.Button, e.Clicks, e.X - m_ctrl_hover.Left, pt.Y - m_ctrl_hover.Top, e.Delta));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected internal virtual void OnMouseHWheel(MouseEventArgs e) {
|
||||||
|
if (m_ctrl_hover != null) {
|
||||||
|
m_ctrl_hover.OnMouseHWheel(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnKeyDown(KeyEventArgs e) {
|
||||||
|
if (m_ctrl_active != null) m_ctrl_active.OnKeyDown(e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnKeyUp(KeyEventArgs e) {
|
||||||
|
if (m_ctrl_active != null) m_ctrl_active.OnKeyUp(e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnKeyPress(KeyPressEventArgs e) {
|
||||||
|
if (m_ctrl_active != null) m_ctrl_active.OnKeyPress(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnMove(EventArgs e) { }
|
||||||
|
protected internal virtual void OnResize(EventArgs e) { }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当所有者发生改变时候发生
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnOwnerChanged() { }
|
||||||
|
/// <summary>
|
||||||
|
/// 当选中状态改变时候发生
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnSelectedChanged() { }
|
||||||
|
/// <summary>
|
||||||
|
/// 当活动状态改变时候发生
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnActiveChanged() { }
|
||||||
|
|
||||||
|
#endregion protected
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重绘Node
|
||||||
|
/// </summary>
|
||||||
|
public void Invalidate() {
|
||||||
|
if (this._Owner != null) {
|
||||||
|
this._Owner.Invalidate(this._Owner.CanvasToControl(new Rectangle(this._Left - 5, this._Top - 5, this._Width + 10, this._Height + 10)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 重绘 Node 指定区域
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rect">Node 指定区域</param>
|
||||||
|
public void Invalidate(Rectangle rect) {
|
||||||
|
rect.X += this._Left;
|
||||||
|
rect.Y += this._Top;
|
||||||
|
if (this._Owner != null) {
|
||||||
|
this._Owner.Invalidate(this._Owner.CanvasToControl(rect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取此Node所包含的输入Option集合
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Option集合</returns>
|
||||||
|
public STNodeOption[] GetInputOptions() {
|
||||||
|
STNodeOption[] ops = new STNodeOption[this._InputOptions.Count];
|
||||||
|
for (int i = 0; i < this._InputOptions.Count; i++) ops[i] = this._InputOptions[i];
|
||||||
|
return ops;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取此Node所包含的输出Option集合
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Option集合</returns>
|
||||||
|
public STNodeOption[] GetOutputOptions() {
|
||||||
|
STNodeOption[] ops = new STNodeOption[this._OutputOptions.Count];
|
||||||
|
for (int i = 0; i < this._OutputOptions.Count; i++) ops[i] = this._OutputOptions[i];
|
||||||
|
return ops;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置Node的选中状态
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bSelected">是否选中</param>
|
||||||
|
/// <param name="bRedraw">是否重绘</param>
|
||||||
|
public void SetSelected(bool bSelected, bool bRedraw) {
|
||||||
|
if (this._IsSelected == bSelected) return;
|
||||||
|
this._IsSelected = bSelected;
|
||||||
|
if (bRedraw) this.Invalidate();
|
||||||
|
this.OnSelectedChanged();
|
||||||
|
}
|
||||||
|
public IAsyncResult BeginInvoke(Delegate method) { return this.BeginInvoke(method, null); }
|
||||||
|
public IAsyncResult BeginInvoke(Delegate method, params object[] args) {
|
||||||
|
if (this._Owner == null) return null;
|
||||||
|
return this._Owner.BeginInvoke(method, args);
|
||||||
|
}
|
||||||
|
public object Invoke(Delegate method) { return this.Invoke(method, null); }
|
||||||
|
public object Invoke(Delegate method, params object[] args) {
|
||||||
|
if (this._Owner == null) return null;
|
||||||
|
return this._Owner.Invoke(method, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
229
ST.Library.UI/STNodeEditor/STNodeCollection.cs
Executable file
@ -0,0 +1,229 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public class STNodeCollection : IList, ICollection, IEnumerable
|
||||||
|
{
|
||||||
|
private int _Count;
|
||||||
|
public int Count { get { return _Count; } }
|
||||||
|
private STNode[] m_nodes;
|
||||||
|
private STNodeEditor m_owner;
|
||||||
|
|
||||||
|
internal STNodeCollection(STNodeEditor owner) {
|
||||||
|
if (owner == null) throw new ArgumentNullException("所有者不能为空");
|
||||||
|
m_owner = owner;
|
||||||
|
m_nodes = new STNode[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Add(STNode node) {
|
||||||
|
if (node == null) throw new ArgumentNullException("添加对象不能为空");
|
||||||
|
this.EnsureSpace(1);
|
||||||
|
int nIndex = this.IndexOf(node);
|
||||||
|
if (-1 == nIndex) {
|
||||||
|
nIndex = this._Count;
|
||||||
|
node.Owner = m_owner;
|
||||||
|
node.BuildSize(true, true, false);
|
||||||
|
m_nodes[this._Count++] = node;
|
||||||
|
m_owner.BuildBounds();
|
||||||
|
m_owner.OnNodeAdded(new STNodeEditorEventArgs(node));
|
||||||
|
m_owner.Invalidate();
|
||||||
|
//m_owner.Invalidate(m_owner.CanvasToControl(new Rectangle(node.Left - 5, node.Top - 5, node.Width + 10, node.Height + 10)));
|
||||||
|
//Console.WriteLine(node.Rectangle);
|
||||||
|
}
|
||||||
|
return nIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRange(STNode[] nodes) {
|
||||||
|
if (nodes == null) throw new ArgumentNullException("添加对象不能为空");
|
||||||
|
this.EnsureSpace(nodes.Length);
|
||||||
|
foreach (var n in nodes) {
|
||||||
|
if (n == null) throw new ArgumentNullException("添加对象不能为空");
|
||||||
|
if (-1 == this.IndexOf(n)) {
|
||||||
|
n.Owner = m_owner;
|
||||||
|
m_nodes[this._Count++] = n;
|
||||||
|
}
|
||||||
|
m_owner.OnNodeAdded(new STNodeEditorEventArgs(n));
|
||||||
|
}
|
||||||
|
m_owner.Invalidate();
|
||||||
|
m_owner.BuildBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear() {
|
||||||
|
for (int i = 0; i < this._Count; i++) {
|
||||||
|
m_nodes[i].Owner = null;
|
||||||
|
foreach (STNodeOption op in m_nodes[i].InputOptions) op.DisConnectionAll();
|
||||||
|
foreach (STNodeOption op in m_nodes[i].OutputOptions) op.DisConnectionAll();
|
||||||
|
m_owner.OnNodeRemoved(new STNodeEditorEventArgs(m_nodes[i]));
|
||||||
|
}
|
||||||
|
this._Count = 0;
|
||||||
|
m_nodes = new STNode[4];
|
||||||
|
m_owner.BuildBounds();
|
||||||
|
m_owner.ScaleCanvas(1, 0, 0); //当不存在节点时候 坐标系回归
|
||||||
|
m_owner.MoveCanvas(10, 10, true, CanvasMoveArgs.All);
|
||||||
|
m_owner.Invalidate(); //如果画布位置和缩放处于初始状态 上面两行代码并不会造成控件重绘
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(STNode node) {
|
||||||
|
return this.IndexOf(node) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IndexOf(STNode node) {
|
||||||
|
return Array.IndexOf<STNode>(m_nodes, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Insert(int nIndex, STNode node) {
|
||||||
|
if (nIndex < 0 || nIndex >= this._Count)
|
||||||
|
throw new IndexOutOfRangeException("索引越界");
|
||||||
|
if (node == null)
|
||||||
|
throw new ArgumentNullException("插入对象不能为空");
|
||||||
|
this.EnsureSpace(1);
|
||||||
|
for (int i = this._Count; i > nIndex; i--)
|
||||||
|
m_nodes[i] = m_nodes[i - 1];
|
||||||
|
node.Owner = m_owner;
|
||||||
|
m_nodes[nIndex] = node;
|
||||||
|
this._Count++;
|
||||||
|
node.BuildSize(true, true,false);
|
||||||
|
m_owner.Invalidate();
|
||||||
|
m_owner.BuildBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFixedSize {
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly {
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(STNode node) {
|
||||||
|
int nIndex = this.IndexOf(node);
|
||||||
|
if (nIndex != -1) this.RemoveAt(nIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAt(int nIndex) {
|
||||||
|
if (nIndex < 0 || nIndex >= this._Count)
|
||||||
|
throw new IndexOutOfRangeException("索引越界");
|
||||||
|
m_nodes[nIndex].Owner = null;
|
||||||
|
m_owner.OnNodeRemoved(new STNodeEditorEventArgs(m_nodes[nIndex]));
|
||||||
|
this._Count--;
|
||||||
|
for (int i = nIndex, Len = this._Count; i < Len; i++)
|
||||||
|
m_nodes[i] = m_nodes[i + 1];
|
||||||
|
if (this._Count == 0) { //当不存在节点时候 坐标系回归
|
||||||
|
m_owner.ScaleCanvas(1, 0, 0);
|
||||||
|
m_owner.MoveCanvas(10, 10, true, CanvasMoveArgs.All);
|
||||||
|
} else {
|
||||||
|
m_owner.Invalidate();
|
||||||
|
m_owner.BuildBounds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public STNode this[int nIndex] {
|
||||||
|
get {
|
||||||
|
if (nIndex < 0 || nIndex >= this._Count)
|
||||||
|
throw new IndexOutOfRangeException("索引越界");
|
||||||
|
return m_nodes[nIndex];
|
||||||
|
}
|
||||||
|
set { throw new InvalidOperationException("禁止重新赋值元素"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(Array array, int index) {
|
||||||
|
if (array == null)
|
||||||
|
throw new ArgumentNullException("数组不能为空");
|
||||||
|
m_nodes.CopyTo(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSynchronized {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public object SyncRoot {
|
||||||
|
get { return this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator GetEnumerator() {
|
||||||
|
for (int i = 0, Len = this._Count; i < Len; i++)
|
||||||
|
yield return m_nodes[i];
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 确认空间是否足够 空间不足扩大容量
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="elements">需要增加的个数</param>
|
||||||
|
private void EnsureSpace(int elements) {
|
||||||
|
if (elements + this._Count > m_nodes.Length) {
|
||||||
|
STNode[] arrTemp = new STNode[Math.Max(m_nodes.Length * 2, elements + this._Count)];
|
||||||
|
m_nodes.CopyTo(arrTemp, 0);
|
||||||
|
m_nodes = arrTemp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//============================================================================
|
||||||
|
int IList.Add(object value) {
|
||||||
|
return this.Add((STNode)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Clear() {
|
||||||
|
this.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IList.Contains(object value) {
|
||||||
|
return this.Contains((STNode)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IList.IndexOf(object value) {
|
||||||
|
return this.IndexOf((STNode)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Insert(int index, object value) {
|
||||||
|
this.Insert(index, (STNode)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IList.IsFixedSize {
|
||||||
|
get { return this.IsFixedSize; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IList.IsReadOnly {
|
||||||
|
get { return this.IsReadOnly; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Remove(object value) {
|
||||||
|
this.Remove((STNode)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.RemoveAt(int index) {
|
||||||
|
this.RemoveAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
object IList.this[int index] {
|
||||||
|
get {
|
||||||
|
return this[index];
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this[index] = (STNode)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICollection.CopyTo(Array array, int index) {
|
||||||
|
this.CopyTo(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ICollection.Count {
|
||||||
|
get { return this._Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICollection.IsSynchronized {
|
||||||
|
get { return this.IsSynchronized; }
|
||||||
|
}
|
||||||
|
|
||||||
|
object ICollection.SyncRoot {
|
||||||
|
get { return this.SyncRoot; }
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() {
|
||||||
|
return this.GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
235
ST.Library.UI/STNodeEditor/STNodeControl.cs
Executable file
@ -0,0 +1,235 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public class STNodeControl
|
||||||
|
{
|
||||||
|
private STNode _Owner;
|
||||||
|
|
||||||
|
public STNode Owner {
|
||||||
|
get { return _Owner; }
|
||||||
|
internal set { _Owner = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Left;
|
||||||
|
|
||||||
|
public int Left {
|
||||||
|
get { return _Left; }
|
||||||
|
set {
|
||||||
|
_Left = value;
|
||||||
|
this.OnMove(new EventArgs());
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Top;
|
||||||
|
|
||||||
|
public int Top {
|
||||||
|
get { return _Top; }
|
||||||
|
set {
|
||||||
|
_Top = value;
|
||||||
|
this.OnMove(new EventArgs());
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Width;
|
||||||
|
|
||||||
|
public int Width {
|
||||||
|
get { return _Width; }
|
||||||
|
set {
|
||||||
|
_Width = value;
|
||||||
|
this.OnResize(new EventArgs());
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Height;
|
||||||
|
|
||||||
|
public int Height {
|
||||||
|
get { return _Height; }
|
||||||
|
set {
|
||||||
|
_Height = value;
|
||||||
|
this.OnResize(new EventArgs());
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point Location {
|
||||||
|
get { return new Point(this._Left, this._Top); }
|
||||||
|
}
|
||||||
|
public Size Size {
|
||||||
|
get { return new Size(this._Width, this._Height); }
|
||||||
|
}
|
||||||
|
public Rectangle DisplayRectangle {
|
||||||
|
get { return new Rectangle(this._Left, this._Top, this._Width, this._Height); }
|
||||||
|
}
|
||||||
|
public Rectangle ClientRectangle {
|
||||||
|
get { return new Rectangle(0, 0, this._Width, this._Height); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _BackColor = Color.FromArgb(127, 0, 0, 0);
|
||||||
|
|
||||||
|
public Color BackColor {
|
||||||
|
get { return _BackColor; }
|
||||||
|
set {
|
||||||
|
_BackColor = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _ForeColor = Color.White;
|
||||||
|
|
||||||
|
public Color ForeColor {
|
||||||
|
get { return _ForeColor; }
|
||||||
|
set {
|
||||||
|
_ForeColor = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _Text = "STNCTRL";
|
||||||
|
|
||||||
|
public string Text {
|
||||||
|
get { return _Text; }
|
||||||
|
set {
|
||||||
|
_Text = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Font _Font;
|
||||||
|
|
||||||
|
public Font Font {
|
||||||
|
get { return _Font; }
|
||||||
|
set {
|
||||||
|
if (value == _Font) return;
|
||||||
|
if (value == null) throw new ArgumentNullException("值不能为空");
|
||||||
|
_Font = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StringFormat m_sf;
|
||||||
|
|
||||||
|
public STNodeControl() {
|
||||||
|
m_sf = new StringFormat();
|
||||||
|
m_sf.Alignment = StringAlignment.Center;
|
||||||
|
m_sf.LineAlignment = StringAlignment.Center;
|
||||||
|
this._Font = new Font("courier new", 8.25f);
|
||||||
|
this.Width = 75;
|
||||||
|
this.Height = 23;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnPaint(DrawingTools dt) {
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
SolidBrush brush = dt.SolidBrush;
|
||||||
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
|
||||||
|
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
|
||||||
|
brush.Color = this._BackColor;
|
||||||
|
g.FillRectangle(brush, 0, 0, this.Width, this.Height);
|
||||||
|
if (!string.IsNullOrEmpty(this._Text)) {
|
||||||
|
brush.Color = this._ForeColor;
|
||||||
|
g.DrawString(this._Text, this._Font, brush, this.ClientRectangle, m_sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Invalidate() {
|
||||||
|
if (this._Owner == null) return;
|
||||||
|
this._Owner.Invalidate(new Rectangle(this._Left, this._Top + this._Owner.TitleHeight, this.Width, this.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Invalidate(Rectangle rect) {
|
||||||
|
if (this._Owner == null) return;
|
||||||
|
this._Owner.Invalidate(this.RectangleToParent(rect));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle RectangleToParent(Rectangle rect) {
|
||||||
|
return new Rectangle(this._Left, this._Top + this._Owner.TitleHeight, this.Width, this.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler GotFocus;
|
||||||
|
public event EventHandler LostFocus;
|
||||||
|
public event EventHandler MouseEnter;
|
||||||
|
public event EventHandler MouseLeave;
|
||||||
|
public event MouseEventHandler MouseDown;
|
||||||
|
public event MouseEventHandler MouseMove;
|
||||||
|
public event MouseEventHandler MouseUp;
|
||||||
|
public event MouseEventHandler MouseClick;
|
||||||
|
public event MouseEventHandler MouseWheel;
|
||||||
|
public event EventHandler MouseHWheel;
|
||||||
|
|
||||||
|
public event KeyEventHandler KeyDown;
|
||||||
|
public event KeyEventHandler KeyUp;
|
||||||
|
public event KeyPressEventHandler KeyPress;
|
||||||
|
|
||||||
|
public event EventHandler Move;
|
||||||
|
public event EventHandler Resize;
|
||||||
|
|
||||||
|
|
||||||
|
protected internal virtual void OnGotFocus(EventArgs e) {
|
||||||
|
if (this.GotFocus != null) this.GotFocus(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnLostFocus(EventArgs e) {
|
||||||
|
if (this.LostFocus != null) this.LostFocus(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnMouseEnter(EventArgs e) {
|
||||||
|
if (this.MouseEnter != null) this.MouseEnter(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnMouseLeave(EventArgs e) {
|
||||||
|
if (this.MouseLeave != null) this.MouseLeave(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnMouseDown(MouseEventArgs e) {
|
||||||
|
if (this.MouseDown != null) this.MouseDown(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnMouseMove(MouseEventArgs e) {
|
||||||
|
if (this.MouseMove != null) this.MouseMove(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnMouseUp(MouseEventArgs e) {
|
||||||
|
if (this.MouseUp != null) this.MouseUp(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnMouseClick(MouseEventArgs e) {
|
||||||
|
if (this.MouseClick != null) this.MouseClick(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnMouseWheel(MouseEventArgs e) {
|
||||||
|
if (this.MouseWheel != null) this.MouseWheel(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnMouseHWheel(MouseEventArgs e) {
|
||||||
|
if (this.MouseHWheel != null) this.MouseHWheel(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnKeyDown(KeyEventArgs e) {
|
||||||
|
if (this.KeyDown != null) this.KeyDown(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnKeyUp(KeyEventArgs e) {
|
||||||
|
if (this.KeyUp != null) this.KeyUp(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnKeyPress(KeyPressEventArgs e) {
|
||||||
|
if (this.KeyPress != null) this.KeyPress(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnMove(EventArgs e) {
|
||||||
|
if (this.Move != null) this.Move(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual void OnResize(EventArgs e) {
|
||||||
|
if (this.Resize != null) this.Resize(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAsyncResult BeginInvoke(Delegate method) { return this.BeginInvoke(method, null); }
|
||||||
|
public IAsyncResult BeginInvoke(Delegate method, params object[] args) {
|
||||||
|
if (this._Owner == null) return null;
|
||||||
|
return this._Owner.BeginInvoke(method, args);
|
||||||
|
}
|
||||||
|
public object Invoke(Delegate method) { return this.Invoke(method, null); }
|
||||||
|
public object Invoke(Delegate method, params object[] args) {
|
||||||
|
if (this._Owner == null) return null;
|
||||||
|
return this._Owner.Invoke(method, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
214
ST.Library.UI/STNodeEditor/STNodeControlCollection.cs
Executable file
@ -0,0 +1,214 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public class STNodeControlCollection: IList, ICollection, IEnumerable
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 为了确保安全在STNode中 仅继承者才能够访问集合
|
||||||
|
*/
|
||||||
|
private int _Count;
|
||||||
|
public int Count { get { return _Count; } }
|
||||||
|
private STNodeControl[] m_controls;
|
||||||
|
private STNode m_owner;
|
||||||
|
|
||||||
|
internal STNodeControlCollection(STNode owner) {
|
||||||
|
if (owner == null) throw new ArgumentNullException("所有者不能为空");
|
||||||
|
m_owner = owner;
|
||||||
|
m_controls = new STNodeControl[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Add(STNodeControl control) {
|
||||||
|
if (control == null) throw new ArgumentNullException("添加对象不能为空");
|
||||||
|
this.EnsureSpace(1);
|
||||||
|
int nIndex = this.IndexOf(control);
|
||||||
|
if (-1 == nIndex) {
|
||||||
|
nIndex = this._Count;
|
||||||
|
control.Owner = m_owner;
|
||||||
|
m_controls[this._Count++] = control;
|
||||||
|
this.Redraw();
|
||||||
|
}
|
||||||
|
return nIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRange(STNodeControl[] controls) {
|
||||||
|
if (controls == null) throw new ArgumentNullException("添加对象不能为空");
|
||||||
|
this.EnsureSpace(controls.Length);
|
||||||
|
foreach (var op in controls) {
|
||||||
|
if (op == null) throw new ArgumentNullException("添加对象不能为空");
|
||||||
|
if (-1 == this.IndexOf(op)) {
|
||||||
|
op.Owner = m_owner;
|
||||||
|
m_controls[this._Count++] = op;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear() {
|
||||||
|
for (int i = 0; i < this._Count; i++) m_controls[i].Owner = null;
|
||||||
|
this._Count = 0;
|
||||||
|
m_controls = new STNodeControl[4];
|
||||||
|
this.Redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(STNodeControl option) {
|
||||||
|
return this.IndexOf(option) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IndexOf(STNodeControl option) {
|
||||||
|
return Array.IndexOf<STNodeControl>(m_controls, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Insert(int index, STNodeControl control) {
|
||||||
|
if (index < 0 || index >= this._Count)
|
||||||
|
throw new IndexOutOfRangeException("索引越界");
|
||||||
|
if (control == null)
|
||||||
|
throw new ArgumentNullException("插入对象不能为空");
|
||||||
|
this.EnsureSpace(1);
|
||||||
|
for (int i = this._Count; i > index; i--)
|
||||||
|
m_controls[i] = m_controls[i - 1];
|
||||||
|
control.Owner = m_owner;
|
||||||
|
m_controls[index] = control;
|
||||||
|
this._Count++;
|
||||||
|
this.Redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFixedSize {
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly {
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(STNodeControl control) {
|
||||||
|
int nIndex = this.IndexOf(control);
|
||||||
|
if (nIndex != -1) this.RemoveAt(nIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAt(int index) {
|
||||||
|
if (index < 0 || index >= this._Count)
|
||||||
|
throw new IndexOutOfRangeException("索引越界");
|
||||||
|
this._Count--;
|
||||||
|
m_controls[index].Owner = null;
|
||||||
|
for (int i = index, Len = this._Count; i < Len; i++)
|
||||||
|
m_controls[i] = m_controls[i + 1];
|
||||||
|
this.Redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public STNodeControl this[int index] {
|
||||||
|
get {
|
||||||
|
if (index < 0 || index >= this._Count)
|
||||||
|
throw new IndexOutOfRangeException("索引越界");
|
||||||
|
return m_controls[index];
|
||||||
|
}
|
||||||
|
set { throw new InvalidOperationException("禁止重新赋值元素"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(Array array, int index) {
|
||||||
|
if (array == null)
|
||||||
|
throw new ArgumentNullException("数组不能为空");
|
||||||
|
m_controls.CopyTo(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSynchronized {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public object SyncRoot {
|
||||||
|
get { return this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator GetEnumerator() {
|
||||||
|
for (int i = 0, Len = this._Count; i < Len; i++)
|
||||||
|
yield return m_controls[i];
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 确认空间是否足够 空间不足扩大容量
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="elements">需要增加的个数</param>
|
||||||
|
private void EnsureSpace(int elements) {
|
||||||
|
if (elements + this._Count > m_controls.Length) {
|
||||||
|
STNodeControl[] arrTemp = new STNodeControl[Math.Max(m_controls.Length * 2, elements + this._Count)];
|
||||||
|
m_controls.CopyTo(arrTemp, 0);
|
||||||
|
m_controls = arrTemp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Redraw() {
|
||||||
|
if (m_owner != null && m_owner.Owner != null) {
|
||||||
|
//m_owner.BuildSize();
|
||||||
|
m_owner.Owner.Invalidate(m_owner.Owner.CanvasToControl(m_owner.Rectangle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//===================================================================================
|
||||||
|
int IList.Add(object value) {
|
||||||
|
return this.Add((STNodeControl)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Clear() {
|
||||||
|
this.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IList.Contains(object value) {
|
||||||
|
return this.Contains((STNodeControl)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IList.IndexOf(object value) {
|
||||||
|
return this.IndexOf((STNodeControl)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Insert(int index, object value) {
|
||||||
|
this.Insert(index, (STNodeControl)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IList.IsFixedSize {
|
||||||
|
get { return this.IsFixedSize; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IList.IsReadOnly {
|
||||||
|
get { return this.IsReadOnly; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Remove(object value) {
|
||||||
|
this.Remove((STNodeControl)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.RemoveAt(int index) {
|
||||||
|
this.RemoveAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
object IList.this[int index] {
|
||||||
|
get {
|
||||||
|
return this[index];
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this[index] = (STNodeControl)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICollection.CopyTo(Array array, int index) {
|
||||||
|
this.CopyTo(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ICollection.Count {
|
||||||
|
get { return this._Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICollection.IsSynchronized {
|
||||||
|
get { return this.IsSynchronized; }
|
||||||
|
}
|
||||||
|
|
||||||
|
object ICollection.SyncRoot {
|
||||||
|
get { return this.SyncRoot; }
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() {
|
||||||
|
return this.GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1909
ST.Library.UI/STNodeEditor/STNodeEditor.cs
Executable file
198
ST.Library.UI/STNodeEditor/STNodeEditorDataType.cs
Executable file
@ -0,0 +1,198 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public enum ConnectionStatus
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 不存在所有者
|
||||||
|
/// </summary>
|
||||||
|
[Description("不存在所有者")]
|
||||||
|
NoOwner,
|
||||||
|
/// <summary>
|
||||||
|
/// 相同的所有者
|
||||||
|
/// </summary>
|
||||||
|
[Description("相同的所有者")]
|
||||||
|
SameOwner,
|
||||||
|
/// <summary>
|
||||||
|
/// 均为输入或者输出选项
|
||||||
|
/// </summary>
|
||||||
|
[Description("均为输入或者输出选项")]
|
||||||
|
SameInputOrOutput,
|
||||||
|
/// <summary>
|
||||||
|
/// 不同的数据类型
|
||||||
|
/// </summary>
|
||||||
|
[Description("不同的数据类型")]
|
||||||
|
ErrorType,
|
||||||
|
/// <summary>
|
||||||
|
/// 单连接节点
|
||||||
|
/// </summary>
|
||||||
|
[Description("单连接节点")]
|
||||||
|
SingleOption,
|
||||||
|
/// <summary>
|
||||||
|
/// 出现环形路径
|
||||||
|
/// </summary>
|
||||||
|
[Description("出现环形路径")]
|
||||||
|
Loop,
|
||||||
|
/// <summary>
|
||||||
|
/// 已存在的连接
|
||||||
|
/// </summary>
|
||||||
|
[Description("已存在的连接")]
|
||||||
|
Exists,
|
||||||
|
/// <summary>
|
||||||
|
/// 已经连接
|
||||||
|
/// </summary>
|
||||||
|
[Description("已经连接")]
|
||||||
|
Connected,
|
||||||
|
/// <summary>
|
||||||
|
/// 连接被断开
|
||||||
|
/// </summary>
|
||||||
|
[Description("连接被断开")]
|
||||||
|
DisConnected,
|
||||||
|
/// <summary>
|
||||||
|
/// 节点被锁定
|
||||||
|
/// </summary>
|
||||||
|
[Description("节点被锁定")]
|
||||||
|
Locked,
|
||||||
|
/// <summary>
|
||||||
|
/// 操作被拒绝
|
||||||
|
/// </summary>
|
||||||
|
[Description("操作被拒绝")]
|
||||||
|
Reject,
|
||||||
|
/// <summary>
|
||||||
|
/// 正在被连接
|
||||||
|
/// </summary>
|
||||||
|
[Description("正在被连接")]
|
||||||
|
Connecting,
|
||||||
|
/// <summary>
|
||||||
|
/// 正在断开连接
|
||||||
|
/// </summary>
|
||||||
|
[Description("正在断开连接")]
|
||||||
|
DisConnecting
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AlertLocation
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Top,
|
||||||
|
Right,
|
||||||
|
Bottom,
|
||||||
|
Center,
|
||||||
|
LeftTop,
|
||||||
|
RightTop,
|
||||||
|
RightBottom,
|
||||||
|
LeftBottom,
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct DrawingTools
|
||||||
|
{
|
||||||
|
public Graphics Graphics;
|
||||||
|
public Pen Pen;
|
||||||
|
public SolidBrush SolidBrush;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CanvasMoveArgs //移动画布时需要的参数 查看->MoveCanvas()
|
||||||
|
{
|
||||||
|
Left = 1, //表示 仅移动 X 坐标
|
||||||
|
Top = 2, //表示 仅移动 Y 坐标
|
||||||
|
All = 4 //表示 X Y 同时移动
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct NodeFindInfo
|
||||||
|
{
|
||||||
|
public STNode Node;
|
||||||
|
public STNodeOption NodeOption;
|
||||||
|
public string Mark;
|
||||||
|
public string[] MarkLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ConnectionInfo
|
||||||
|
{
|
||||||
|
public STNodeOption Input;
|
||||||
|
public STNodeOption Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void STNodeOptionEventHandler(object sender, STNodeOptionEventArgs e);
|
||||||
|
|
||||||
|
public class STNodeOptionEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
private STNodeOption _TargetOption;
|
||||||
|
/// <summary>
|
||||||
|
/// 触发此事件的对应Option
|
||||||
|
/// </summary>
|
||||||
|
public STNodeOption TargetOption {
|
||||||
|
get { return _TargetOption; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectionStatus _Status;
|
||||||
|
/// <summary>
|
||||||
|
/// Option之间的连线状态
|
||||||
|
/// </summary>
|
||||||
|
public ConnectionStatus Status {
|
||||||
|
get { return _Status; }
|
||||||
|
internal set { _Status = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _IsSponsor;
|
||||||
|
/// <summary>
|
||||||
|
/// 是否为此次行为的发起者
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSponsor {
|
||||||
|
get { return _IsSponsor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public STNodeOptionEventArgs(bool isSponsor, STNodeOption opTarget, ConnectionStatus cr) {
|
||||||
|
this._IsSponsor = isSponsor;
|
||||||
|
this._TargetOption = opTarget;
|
||||||
|
this._Status = cr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void STNodeEditorEventHandler(object sender, STNodeEditorEventArgs e);
|
||||||
|
public delegate void STNodeEditorOptionEventHandler(object sender, STNodeEditorOptionEventArgs e);
|
||||||
|
|
||||||
|
|
||||||
|
public class STNodeEditorEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
private STNode _Node;
|
||||||
|
|
||||||
|
public STNode Node {
|
||||||
|
get { return _Node; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public STNodeEditorEventArgs(STNode node) {
|
||||||
|
this._Node = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class STNodeEditorOptionEventArgs : STNodeOptionEventArgs
|
||||||
|
{
|
||||||
|
|
||||||
|
private STNodeOption _CurrentOption;
|
||||||
|
/// <summary>
|
||||||
|
/// 主动触发事件的Option
|
||||||
|
/// </summary>
|
||||||
|
public STNodeOption CurrentOption {
|
||||||
|
get { return _CurrentOption; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _Continue = true;
|
||||||
|
/// <summary>
|
||||||
|
/// 是否继续向下操作 用于Begin(Connecting/DisConnecting)是否继续向后操作
|
||||||
|
/// </summary>
|
||||||
|
public bool Continue {
|
||||||
|
get { return _Continue; }
|
||||||
|
set { _Continue = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public STNodeEditorOptionEventArgs(STNodeOption opTarget, STNodeOption opCurrent, ConnectionStatus cr)
|
||||||
|
: base(false, opTarget, cr) {
|
||||||
|
this._CurrentOption = opCurrent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
147
ST.Library.UI/STNodeEditor/STNodeHub.cs
Executable file
@ -0,0 +1,147 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public class STNodeHub : STNode
|
||||||
|
{
|
||||||
|
private bool m_bSingle;
|
||||||
|
private string m_strIn;
|
||||||
|
private string m_strOut;
|
||||||
|
|
||||||
|
public STNodeHub() : this(false, "IN", "OUT") { }
|
||||||
|
public STNodeHub(bool bSingle) : this(bSingle, "IN", "OUT") { }
|
||||||
|
public STNodeHub(bool bSingle, string strTextIn, string strTextOut) {
|
||||||
|
m_bSingle = bSingle;
|
||||||
|
m_strIn = strTextIn;
|
||||||
|
m_strOut = strTextOut;
|
||||||
|
this.Addhub();
|
||||||
|
this.Title = "HUB";
|
||||||
|
this.TitleColor = System.Drawing.Color.FromArgb(200, System.Drawing.Color.DarkOrange);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Addhub() {
|
||||||
|
var input = new STNodeHubOption(m_strIn, typeof(object), m_bSingle);
|
||||||
|
var output = new STNodeHubOption(m_strOut, typeof(object), false);
|
||||||
|
this.InputOptions.Add(input);
|
||||||
|
this.OutputOptions.Add(output);
|
||||||
|
input.Connected += new STNodeOptionEventHandler(input_Connected);
|
||||||
|
input.DataTransfer += new STNodeOptionEventHandler(input_DataTransfer);
|
||||||
|
input.DisConnected += new STNodeOptionEventHandler(input_DisConnected);
|
||||||
|
output.Connected += new STNodeOptionEventHandler(output_Connected);
|
||||||
|
output.DisConnected += new STNodeOptionEventHandler(output_DisConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_DisConnected(object sender, STNodeOptionEventArgs e) {
|
||||||
|
STNodeOption op = sender as STNodeOption;
|
||||||
|
if (op.ConnectionCount != 0) return;
|
||||||
|
int nIndex = this.OutputOptions.IndexOf(op);
|
||||||
|
if (this.InputOptions[nIndex].ConnectionCount != 0) return;
|
||||||
|
this.InputOptions.RemoveAt(nIndex);
|
||||||
|
this.OutputOptions.RemoveAt(nIndex);
|
||||||
|
if (this.Owner != null) this.Owner.BuildLinePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_Connected(object sender, STNodeOptionEventArgs e) {
|
||||||
|
STNodeOption op = sender as STNodeOption;
|
||||||
|
int nIndex = this.OutputOptions.IndexOf(op);
|
||||||
|
var t = typeof(object);
|
||||||
|
if (this.InputOptions[nIndex].DataType == t) {
|
||||||
|
op.DataType = e.TargetOption.DataType;
|
||||||
|
this.InputOptions[nIndex].DataType = op.DataType;
|
||||||
|
foreach (STNodeOption v in this.InputOptions) {
|
||||||
|
if (v.DataType == t) return;
|
||||||
|
}
|
||||||
|
this.Addhub();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void input_DisConnected(object sender, STNodeOptionEventArgs e) {
|
||||||
|
STNodeOption op = sender as STNodeOption;
|
||||||
|
if (op.ConnectionCount != 0) return;
|
||||||
|
int nIndex = this.InputOptions.IndexOf(op);
|
||||||
|
if (this.OutputOptions[nIndex].ConnectionCount != 0) return;
|
||||||
|
this.InputOptions.RemoveAt(nIndex);
|
||||||
|
this.OutputOptions.RemoveAt(nIndex);
|
||||||
|
if (this.Owner != null) this.Owner.BuildLinePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
void input_DataTransfer(object sender, STNodeOptionEventArgs e) {
|
||||||
|
STNodeOption op = sender as STNodeOption;
|
||||||
|
int nIndex = this.InputOptions.IndexOf(op);
|
||||||
|
if (e.Status != ConnectionStatus.Connected)
|
||||||
|
this.OutputOptions[nIndex].Data = null;
|
||||||
|
else
|
||||||
|
this.OutputOptions[nIndex].Data = e.TargetOption.Data;
|
||||||
|
this.OutputOptions[nIndex].TransferData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void input_Connected(object sender, STNodeOptionEventArgs e) {
|
||||||
|
STNodeOption op = sender as STNodeOption;
|
||||||
|
int nIndex = this.InputOptions.IndexOf(op);
|
||||||
|
var t = typeof(object);
|
||||||
|
if (op.DataType == t) {
|
||||||
|
op.DataType = e.TargetOption.DataType;
|
||||||
|
this.OutputOptions[nIndex].DataType = op.DataType;
|
||||||
|
foreach (STNodeOption v in this.InputOptions) {
|
||||||
|
if (v.DataType == t) return;
|
||||||
|
}
|
||||||
|
this.Addhub();
|
||||||
|
} else {
|
||||||
|
//this.OutputOptions[nIndex].Data = e.TargetOption.Data;
|
||||||
|
this.OutputOptions[nIndex].TransferData(e.TargetOption.Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnSaveNode(Dictionary<string,byte[]> dic) {
|
||||||
|
dic.Add("count", BitConverter.GetBytes(this.InputOptionsCount));
|
||||||
|
dic.Add("single", new byte[] { (byte)(m_bSingle ? 1 : 0) });
|
||||||
|
dic.Add("strin", Encoding.UTF8.GetBytes(m_strIn));
|
||||||
|
dic.Add("strout", Encoding.UTF8.GetBytes(m_strOut));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal override void OnLoadNode(Dictionary<string, byte[]> dic) {
|
||||||
|
base.OnLoadNode(dic);
|
||||||
|
int nCount = BitConverter.ToInt32(dic["count"], 0);
|
||||||
|
while (this.InputOptionsCount < nCount && this.InputOptionsCount != nCount) this.Addhub();
|
||||||
|
m_bSingle = dic["single"][0] == 1;
|
||||||
|
m_strIn = Encoding.UTF8.GetString(dic["strin"]);
|
||||||
|
m_strOut = Encoding.UTF8.GetString(dic["strout"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class STNodeHubOption : STNodeOption
|
||||||
|
{
|
||||||
|
public STNodeHubOption(string strText, Type dataType, bool bSingle) : base(strText, dataType, bSingle) { }
|
||||||
|
|
||||||
|
public override ConnectionStatus ConnectOption(STNodeOption op) {
|
||||||
|
var t = typeof(object);
|
||||||
|
if (this.DataType != t) return base.ConnectOption(op);
|
||||||
|
this.DataType = op.DataType;
|
||||||
|
var ret = base.ConnectOption(op);
|
||||||
|
if (ret != ConnectionStatus.Connected) this.DataType = t;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ConnectionStatus CanConnect(STNodeOption op) {
|
||||||
|
if (this.DataType != typeof(object)) return base.CanConnect(op);
|
||||||
|
if (this.IsInput == op.IsInput) return ConnectionStatus.SameInputOrOutput;
|
||||||
|
if (op.Owner == this.Owner) return ConnectionStatus.SameOwner;
|
||||||
|
if (op.Owner == null || this.Owner == null) return ConnectionStatus.NoOwner;
|
||||||
|
if (this.IsSingle && m_hs_connected.Count == 1) return ConnectionStatus.SingleOption;
|
||||||
|
if (op.IsInput && STNodeEditor.CanFindNodePath(op.Owner, this.Owner)) return ConnectionStatus.Loop;
|
||||||
|
if (m_hs_connected.Contains(op)) return ConnectionStatus.Exists;
|
||||||
|
if (op.DataType == typeof(object)) return ConnectionStatus.ErrorType;
|
||||||
|
|
||||||
|
if (!this.IsInput) return ConnectionStatus.Connected;
|
||||||
|
foreach (STNodeOption owner_input in this.Owner.InputOptions) {
|
||||||
|
foreach (STNodeOption o in owner_input.ConnectedOption) {
|
||||||
|
if (o == op) return ConnectionStatus.Exists;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ConnectionStatus.Connected; ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
421
ST.Library.UI/STNodeEditor/STNodeOption.cs
Executable file
@ -0,0 +1,421 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public class STNodeOption
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
private STNode _Owner;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 所属的 Node
|
||||||
|
/// </summary>
|
||||||
|
public STNode Owner {
|
||||||
|
get { return _Owner; }
|
||||||
|
internal set {
|
||||||
|
if (value == _Owner) return;
|
||||||
|
if (_Owner != null) this.DisConnectionAll(); //当所有者变更时 断开当前所有连接
|
||||||
|
_Owner = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _IsSingle;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 是否仅能被连接一次
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSingle {
|
||||||
|
get { return _IsSingle; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _IsInput;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 是否是输入选项
|
||||||
|
/// </summary>
|
||||||
|
public bool IsInput {
|
||||||
|
get { return _IsInput; }
|
||||||
|
internal set { _IsInput = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _TextColor = Color.White;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置当前 Option 文本颜色
|
||||||
|
/// </summary>
|
||||||
|
public Color TextColor {
|
||||||
|
get { return _TextColor; }
|
||||||
|
protected set {
|
||||||
|
if (value == _TextColor) return;
|
||||||
|
_TextColor = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _DotColor = Color.Transparent;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置当前 Option 连接点的颜色
|
||||||
|
/// </summary>
|
||||||
|
public Color DotColor {
|
||||||
|
get { return _DotColor; }
|
||||||
|
protected set {
|
||||||
|
if (value == _DotColor) return;
|
||||||
|
_DotColor = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _Text;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置当前 Option 显示文本
|
||||||
|
/// </summary>
|
||||||
|
public string Text {
|
||||||
|
get { return _Text; }
|
||||||
|
protected set {
|
||||||
|
if (value == _Text) return;
|
||||||
|
_Text = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _DotLeft;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 连接点的左边坐标
|
||||||
|
/// </summary>
|
||||||
|
public int DotLeft {
|
||||||
|
get { return _DotLeft; }
|
||||||
|
internal set { _DotLeft = value; }
|
||||||
|
}
|
||||||
|
private int _DotTop;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 连接点的上边坐标
|
||||||
|
/// </summary>
|
||||||
|
public int DotTop {
|
||||||
|
get { return _DotTop; }
|
||||||
|
internal set { _DotTop = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _DotSize;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 连接点的宽度
|
||||||
|
/// </summary>
|
||||||
|
public int DotSize {
|
||||||
|
get { return _DotSize; }
|
||||||
|
protected internal set { _DotSize = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private object _Data;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或者设置当前 Option 所包含的数据
|
||||||
|
/// </summary>
|
||||||
|
public object Data {
|
||||||
|
get { return _Data; }
|
||||||
|
set {
|
||||||
|
if (value != null) {
|
||||||
|
var t = value.GetType();
|
||||||
|
if (t != this._DataType && !t.IsSubclassOf(this._DataType)) {
|
||||||
|
throw new ArgumentException("无效数据类型 数据类型必须为指定的数据类型或其子类");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_Data = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type _DataType;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 数据类型
|
||||||
|
/// </summary>
|
||||||
|
public Type DataType {
|
||||||
|
get { return _DataType; }
|
||||||
|
internal set { _DataType = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
//private Rectangle _DotRectangle;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 连接点的区域
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle DotRectangle {
|
||||||
|
get {
|
||||||
|
return new Rectangle(this._DotLeft, this._DotTop, this._DotSize, this._DotSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 被连接的个数
|
||||||
|
/// </summary>
|
||||||
|
public int ConnectionCount {
|
||||||
|
get { return m_hs_connected.Count; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 所连接的 Option 集合
|
||||||
|
/// </summary>
|
||||||
|
internal HashSet<STNodeOption> ConnectedOption {
|
||||||
|
get { return m_hs_connected; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
/// <summary>
|
||||||
|
/// 保存已经被连接的点
|
||||||
|
/// </summary>
|
||||||
|
protected HashSet<STNodeOption> m_hs_connected;
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个 Option
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="strText">显示文本</param>
|
||||||
|
/// <param name="dataType">数据类型</param>
|
||||||
|
/// <param name="bSingle">是否为单连接</param>
|
||||||
|
public STNodeOption(string strText, Type dataType, bool bSingle) {
|
||||||
|
if (dataType == null) throw new ArgumentNullException("指定的数据类型不能为空");
|
||||||
|
this._DotSize = 10;
|
||||||
|
m_hs_connected = new HashSet<STNodeOption>();
|
||||||
|
this._DataType = dataType;
|
||||||
|
this._Text = strText;
|
||||||
|
this._IsSingle = bSingle;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructor
|
||||||
|
|
||||||
|
#region Event
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当被连接时候发生
|
||||||
|
/// </summary>
|
||||||
|
public event STNodeOptionEventHandler Connected;
|
||||||
|
/// <summary>
|
||||||
|
/// 当连接开始发生时发生
|
||||||
|
/// </summary>
|
||||||
|
public event STNodeOptionEventHandler Connecting;
|
||||||
|
/// <summary>
|
||||||
|
/// 当连接断开时候发生
|
||||||
|
/// </summary>
|
||||||
|
public event STNodeOptionEventHandler DisConnected;
|
||||||
|
/// <summary>
|
||||||
|
/// 当连接开始断开时发生
|
||||||
|
/// </summary>
|
||||||
|
public event STNodeOptionEventHandler DisConnecting;
|
||||||
|
/// <summary>
|
||||||
|
/// 当有数据传递时候发生
|
||||||
|
/// </summary>
|
||||||
|
public event STNodeOptionEventHandler DataTransfer;
|
||||||
|
|
||||||
|
#endregion Event
|
||||||
|
|
||||||
|
#region protected
|
||||||
|
/// <summary>
|
||||||
|
/// 重绘整个控件
|
||||||
|
/// </summary>
|
||||||
|
protected void Invalidate() {
|
||||||
|
if (this._Owner == null) return;
|
||||||
|
this._Owner.Invalidate();
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* 开始我认为应当只有输入类型的选项才具有事件 因为输入是被动的 而输出则是主动的
|
||||||
|
* 但是后来发现 比如在STNodeHub中输出节点就用到了事件
|
||||||
|
* 以防万一所以这里代码注释起来了 也并不是很有问题 输出选项不注册事件也是一样的效果
|
||||||
|
*/
|
||||||
|
protected internal virtual void OnConnected(STNodeOptionEventArgs e) {
|
||||||
|
if (this.Connected != null/* && this._IsInput*/) this.Connected(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnConnecting(STNodeOptionEventArgs e) {
|
||||||
|
if (this.Connecting != null) this.Connecting(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnDisConnected(STNodeOptionEventArgs e) {
|
||||||
|
if (this.DisConnected != null/* && this._IsInput*/) this.DisConnected(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnDisConnecting(STNodeOptionEventArgs e) {
|
||||||
|
if (this.DisConnecting != null) this.DisConnecting(this, e);
|
||||||
|
}
|
||||||
|
protected internal virtual void OnDataTransfer(STNodeOptionEventArgs e) {
|
||||||
|
if (this.DataTransfer != null/* && this._IsInput*/) this.DataTransfer(this, e);
|
||||||
|
}
|
||||||
|
protected void STNodeEidtorConnected(STNodeEditorOptionEventArgs e) {
|
||||||
|
if (this._Owner == null) return;
|
||||||
|
if (this._Owner.Owner == null) return;
|
||||||
|
this._Owner.Owner.OnOptionConnected(e);
|
||||||
|
}
|
||||||
|
protected void STNodeEidtorDisConnected(STNodeEditorOptionEventArgs e) {
|
||||||
|
if (this._Owner == null) return;
|
||||||
|
if (this._Owner.Owner == null) return;
|
||||||
|
this._Owner.Owner.OnOptionDisConnected(e);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 当前 Option 开始连接目标 Option
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="op">需要连接的 Option</param>
|
||||||
|
/// <returns>是否允许继续操作</returns>
|
||||||
|
protected virtual bool ConnectingOption(STNodeOption op) {
|
||||||
|
if (this._Owner == null) return false;
|
||||||
|
if (this._Owner.Owner == null) return false;
|
||||||
|
STNodeEditorOptionEventArgs e = new STNodeEditorOptionEventArgs(op, this, ConnectionStatus.Connecting);
|
||||||
|
this._Owner.Owner.OnOptionConnecting(e);
|
||||||
|
this.OnConnecting(new STNodeOptionEventArgs(true, op, ConnectionStatus.Connecting));
|
||||||
|
op.OnConnecting(new STNodeOptionEventArgs(false, this, ConnectionStatus.Connecting));
|
||||||
|
return e.Continue;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 当前 Option 开始断开目标 Option
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="op">需要断开的 Option</param>
|
||||||
|
/// <returns>是否允许继续操作</returns>
|
||||||
|
protected virtual bool DisConnectingOption(STNodeOption op) {
|
||||||
|
if (this._Owner == null) return false;
|
||||||
|
if (this._Owner.Owner == null) return false;
|
||||||
|
STNodeEditorOptionEventArgs e = new STNodeEditorOptionEventArgs(op, this, ConnectionStatus.DisConnecting);
|
||||||
|
this._Owner.Owner.OnOptionDisConnecting(e);
|
||||||
|
this.OnDisConnecting(new STNodeOptionEventArgs(true, op, ConnectionStatus.DisConnecting));
|
||||||
|
op.OnDisConnecting(new STNodeOptionEventArgs(false, this, ConnectionStatus.DisConnecting));
|
||||||
|
return e.Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion protected
|
||||||
|
|
||||||
|
#region public
|
||||||
|
/// <summary>
|
||||||
|
/// 当前 Option 连接目标 Option
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="op">需要连接的 Option</param>
|
||||||
|
/// <returns>连接结果</returns>
|
||||||
|
public virtual ConnectionStatus ConnectOption(STNodeOption op) {
|
||||||
|
if (!this.ConnectingOption(op)) {
|
||||||
|
this.STNodeEidtorConnected(new STNodeEditorOptionEventArgs(op, this, ConnectionStatus.Reject));
|
||||||
|
return ConnectionStatus.Reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
var v = this.CanConnect(op);
|
||||||
|
if (v != ConnectionStatus.Connected) {
|
||||||
|
this.STNodeEidtorConnected(new STNodeEditorOptionEventArgs(op, this, v));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
v = op.CanConnect(this);
|
||||||
|
if (v != ConnectionStatus.Connected) {
|
||||||
|
this.STNodeEidtorConnected(new STNodeEditorOptionEventArgs(op, this, v));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
op.AddConnection(this, false);
|
||||||
|
this.AddConnection(op, true);
|
||||||
|
this.ControlBuildLinePath();
|
||||||
|
|
||||||
|
this.STNodeEidtorConnected(new STNodeEditorOptionEventArgs(op, this, v));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 检测当前 Option 是否可以连接目标 Option
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="op">需要连接的 Option</param>
|
||||||
|
/// <returns>检测结果</returns>
|
||||||
|
public virtual ConnectionStatus CanConnect(STNodeOption op) {
|
||||||
|
if (this._IsInput == op.IsInput) return ConnectionStatus.SameInputOrOutput;
|
||||||
|
if (op.Owner == this._Owner) return ConnectionStatus.SameOwner;
|
||||||
|
if (op.Owner == null || this._Owner == null) return ConnectionStatus.NoOwner;
|
||||||
|
if (this._IsSingle && m_hs_connected.Count == 1) return ConnectionStatus.SingleOption;
|
||||||
|
if (op.IsInput && STNodeEditor.CanFindNodePath(op.Owner, this._Owner)) return ConnectionStatus.Loop;
|
||||||
|
if (m_hs_connected.Contains(op)) return ConnectionStatus.Exists;
|
||||||
|
if (this._IsInput && op.DataType != this._DataType && !op.DataType.IsSubclassOf(this._DataType)) return ConnectionStatus.ErrorType;
|
||||||
|
if (this._Owner.LockOption) return ConnectionStatus.Locked;
|
||||||
|
return ConnectionStatus.Connected;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 当前 Option 断开目标 Option
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="op">需要断开的 Option</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual ConnectionStatus DisConnectOption(STNodeOption op) {
|
||||||
|
if (!this.DisConnectingOption(op)) {
|
||||||
|
this.STNodeEidtorDisConnected(new STNodeEditorOptionEventArgs(op, this, ConnectionStatus.Reject));
|
||||||
|
return ConnectionStatus.Reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.Owner == null) return ConnectionStatus.NoOwner;
|
||||||
|
if (this._Owner == null) return ConnectionStatus.NoOwner;
|
||||||
|
if (op.Owner.LockOption && this._Owner.LockOption) {
|
||||||
|
this.STNodeEidtorDisConnected(new STNodeEditorOptionEventArgs(op, this, ConnectionStatus.Locked));
|
||||||
|
return ConnectionStatus.Locked;
|
||||||
|
}
|
||||||
|
op.RemoveConnection(this, false);
|
||||||
|
this.RemoveConnection(op, true);
|
||||||
|
this.ControlBuildLinePath();
|
||||||
|
|
||||||
|
this.STNodeEidtorDisConnected(new STNodeEditorOptionEventArgs(op, this, ConnectionStatus.DisConnected));
|
||||||
|
return ConnectionStatus.DisConnected;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 断开当前 Option 的所有连接
|
||||||
|
/// </summary>
|
||||||
|
public void DisConnectionAll() {
|
||||||
|
var arr = m_hs_connected.ToArray();
|
||||||
|
foreach (var v in arr) {
|
||||||
|
this.DisConnectOption(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前 Option 所连接的 Option 集合
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>如果为null 则表示不存在所有者 否则返回集合</returns>
|
||||||
|
public List<STNodeOption> GetConnectedOption() {
|
||||||
|
if (!this._IsInput)
|
||||||
|
return m_hs_connected.ToList();
|
||||||
|
List<STNodeOption> lst = new List<STNodeOption>();
|
||||||
|
if (this._Owner == null) return null;
|
||||||
|
if (this._Owner.Owner == null) return null;
|
||||||
|
foreach (var v in this._Owner.Owner.GetConnectionInfo()) {
|
||||||
|
if (v.Output == this) lst.Add(v.Input);
|
||||||
|
}
|
||||||
|
return lst;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 向当前 Option 所连接的所有 Option 投递数据
|
||||||
|
/// </summary>
|
||||||
|
public void TransferData() {
|
||||||
|
foreach (var v in m_hs_connected) {
|
||||||
|
v.OnDataTransfer(new STNodeOptionEventArgs(true, this, ConnectionStatus.Connected));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 向当前 Option 所连接的所有 Option 投递数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">需要投递的数据</param>
|
||||||
|
public void TransferData(object data) {
|
||||||
|
this.Data = data; //不是this._Data
|
||||||
|
foreach (var v in m_hs_connected) {
|
||||||
|
v.OnDataTransfer(new STNodeOptionEventArgs(true, this, ConnectionStatus.Connected));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion public
|
||||||
|
|
||||||
|
#region internal
|
||||||
|
|
||||||
|
private bool AddConnection(STNodeOption op, bool bSponsor) {
|
||||||
|
bool b = m_hs_connected.Add(op);
|
||||||
|
this.OnConnected(new STNodeOptionEventArgs(bSponsor, op, ConnectionStatus.Connected));
|
||||||
|
if (this._IsInput) this.OnDataTransfer(new STNodeOptionEventArgs(bSponsor, op, ConnectionStatus.Connected));
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool RemoveConnection(STNodeOption op, bool bSponsor) {
|
||||||
|
bool b = false;
|
||||||
|
if (m_hs_connected.Contains(op)) {
|
||||||
|
b = m_hs_connected.Remove(op);
|
||||||
|
if (this._IsInput) this.OnDataTransfer(new STNodeOptionEventArgs(bSponsor, op, ConnectionStatus.DisConnected));
|
||||||
|
this.OnDisConnected(new STNodeOptionEventArgs(bSponsor, op, ConnectionStatus.Connected));
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion internal
|
||||||
|
|
||||||
|
#region private
|
||||||
|
|
||||||
|
private void ControlBuildLinePath() {
|
||||||
|
if (this.Owner == null) return;
|
||||||
|
if (this.Owner.Owner == null) return;
|
||||||
|
this.Owner.Owner.BuildLinePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
224
ST.Library.UI/STNodeEditor/STNodeOptionCollection.cs
Executable file
@ -0,0 +1,224 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public class STNodeOptionCollection : IList, ICollection, IEnumerable
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 虽然该集合提供了完整的数据接口 如:Add,Remove,...
|
||||||
|
* 但是尽可能的不要使用移除的一些操作 如:Remove,RemoveAt,Clear,this[index] = value,...
|
||||||
|
* 因为在我的定义里面 每个Option的Owner是严格绑定的 一些移除或替换等操作会影响到Owner的变更
|
||||||
|
* 所以原本的所有连线将会断开 并且触发DisConnect事件
|
||||||
|
* 为了确保安全在STNode中 仅继承者才能够访问集合
|
||||||
|
*/
|
||||||
|
private int _Count;
|
||||||
|
public int Count { get { return _Count; } }
|
||||||
|
private STNodeOption[] m_options;
|
||||||
|
private STNode m_owner;
|
||||||
|
|
||||||
|
private bool m_isInput; //当前集合是否是存放的是输入点
|
||||||
|
|
||||||
|
internal STNodeOptionCollection(STNode owner, bool isInput) {
|
||||||
|
if (owner == null) throw new ArgumentNullException("所有者不能为空");
|
||||||
|
m_owner = owner;
|
||||||
|
m_isInput = isInput;
|
||||||
|
m_options = new STNodeOption[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Add(STNodeOption option) {
|
||||||
|
if (option == null) throw new ArgumentNullException("添加对象不能为空");
|
||||||
|
this.EnsureSpace(1);
|
||||||
|
int nIndex = this.IndexOf(option);
|
||||||
|
if (-1 == nIndex) {
|
||||||
|
nIndex = this._Count;
|
||||||
|
option.Owner = m_owner;
|
||||||
|
option.IsInput = m_isInput;
|
||||||
|
m_options[this._Count++] = option;
|
||||||
|
this.Redraw();
|
||||||
|
}
|
||||||
|
return nIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRange(STNodeOption[] options) {
|
||||||
|
if (options == null) throw new ArgumentNullException("添加对象不能为空");
|
||||||
|
this.EnsureSpace(options.Length);
|
||||||
|
foreach (var op in options) {
|
||||||
|
if (op == null) throw new ArgumentNullException("添加对象不能为空");
|
||||||
|
if (-1 == this.IndexOf(op)) {
|
||||||
|
op.Owner = m_owner;
|
||||||
|
op.IsInput = m_isInput;
|
||||||
|
m_options[this._Count++] = op;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear() {
|
||||||
|
for (int i = 0; i < this._Count; i++) m_options[i].Owner = null;
|
||||||
|
this._Count = 0;
|
||||||
|
m_options = new STNodeOption[4];
|
||||||
|
this.Redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(STNodeOption option) {
|
||||||
|
return this.IndexOf(option) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IndexOf(STNodeOption option) {
|
||||||
|
return Array.IndexOf<STNodeOption>(m_options, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Insert(int index, STNodeOption option) {
|
||||||
|
if (index < 0 || index >= this._Count)
|
||||||
|
throw new IndexOutOfRangeException("索引越界");
|
||||||
|
if (option == null)
|
||||||
|
throw new ArgumentNullException("插入对象不能为空");
|
||||||
|
this.EnsureSpace(1);
|
||||||
|
for (int i = this._Count; i > index; i--)
|
||||||
|
m_options[i] = m_options[i - 1];
|
||||||
|
option.Owner = m_owner;
|
||||||
|
m_options[index] = option;
|
||||||
|
this._Count++;
|
||||||
|
this.Redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFixedSize {
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly {
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(STNodeOption option) {
|
||||||
|
int nIndex = this.IndexOf(option);
|
||||||
|
if (nIndex != -1) this.RemoveAt(nIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAt(int index) {
|
||||||
|
if (index < 0 || index >= this._Count)
|
||||||
|
throw new IndexOutOfRangeException("索引越界");
|
||||||
|
this._Count--;
|
||||||
|
m_options[index].Owner = null;
|
||||||
|
for (int i = index, Len = this._Count; i < Len; i++)
|
||||||
|
m_options[i] = m_options[i + 1];
|
||||||
|
this.Redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public STNodeOption this[int index] {
|
||||||
|
get {
|
||||||
|
if (index < 0 || index >= this._Count)
|
||||||
|
throw new IndexOutOfRangeException("索引越界");
|
||||||
|
return m_options[index];
|
||||||
|
}
|
||||||
|
set { throw new InvalidOperationException("禁止重新赋值元素"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(Array array, int index) {
|
||||||
|
if (array == null)
|
||||||
|
throw new ArgumentNullException("数组不能为空");
|
||||||
|
m_options.CopyTo(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSynchronized {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public object SyncRoot {
|
||||||
|
get { return this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator GetEnumerator() {
|
||||||
|
for (int i = 0, Len = this._Count; i < Len; i++)
|
||||||
|
yield return m_options[i];
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 确认空间是否足够 空间不足扩大容量
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="elements">需要增加的个数</param>
|
||||||
|
private void EnsureSpace(int elements) {
|
||||||
|
if (elements + this._Count > m_options.Length) {
|
||||||
|
STNodeOption[] arrTemp = new STNodeOption[Math.Max(m_options.Length * 2, elements + this._Count)];
|
||||||
|
m_options.CopyTo(arrTemp, 0);
|
||||||
|
m_options = arrTemp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Redraw() {
|
||||||
|
if (m_owner != null && m_owner.Owner != null) {
|
||||||
|
m_owner.BuildSize(true, true, true);
|
||||||
|
//m_owner.Invalidate();//.Owner.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//===================================================================================
|
||||||
|
int IList.Add(object value) {
|
||||||
|
return this.Add((STNodeOption)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Clear() {
|
||||||
|
this.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IList.Contains(object value) {
|
||||||
|
return this.Contains((STNodeOption)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IList.IndexOf(object value) {
|
||||||
|
return this.IndexOf((STNodeOption)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Insert(int index, object value) {
|
||||||
|
this.Insert(index, (STNodeOption)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IList.IsFixedSize {
|
||||||
|
get { return this.IsFixedSize; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IList.IsReadOnly {
|
||||||
|
get { return this.IsReadOnly; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Remove(object value) {
|
||||||
|
this.Remove((STNodeOption)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.RemoveAt(int index) {
|
||||||
|
this.RemoveAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
object IList.this[int index] {
|
||||||
|
get {
|
||||||
|
return this[index];
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this[index] = (STNodeOption)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICollection.CopyTo(Array array, int index) {
|
||||||
|
this.CopyTo(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ICollection.Count {
|
||||||
|
get { return this._Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICollection.IsSynchronized {
|
||||||
|
get { return this.IsSynchronized; }
|
||||||
|
}
|
||||||
|
|
||||||
|
object ICollection.SyncRoot {
|
||||||
|
get { return this.SyncRoot; }
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() {
|
||||||
|
return this.GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
WinNodeEditerTest.sln
Executable file
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||||
|
# Visual Studio 2010
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinNodeEditerTest", "WinNodeEditerTest\WinNodeEditerTest.csproj", "{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ST.Library.UI", "ST.Library.UI\ST.Library.UI.csproj", "{EFFCC270-4999-4077-A543-56CCCCE92147}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|Mixed Platforms = Release|Mixed Platforms
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
|
{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||||
|
{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||||
|
{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
|
{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||||
|
{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||||
|
{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}.Release|x86.Build.0 = Release|x86
|
||||||
|
{EFFCC270-4999-4077-A543-56CCCCE92147}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EFFCC270-4999-4077-A543-56CCCCE92147}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EFFCC270-4999-4077-A543-56CCCCE92147}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{EFFCC270-4999-4077-A543-56CCCCE92147}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{EFFCC270-4999-4077-A543-56CCCCE92147}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{EFFCC270-4999-4077-A543-56CCCCE92147}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EFFCC270-4999-4077-A543-56CCCCE92147}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EFFCC270-4999-4077-A543-56CCCCE92147}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{EFFCC270-4999-4077-A543-56CCCCE92147}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{EFFCC270-4999-4077-A543-56CCCCE92147}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
BIN
WinNodeEditerTest.suo
Executable file
25
WinNodeEditerTest/DemoNode.cs
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public class DemoNode : STNode
|
||||||
|
{
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
this.InputOptions.Add(new STNodeOption("Input", typeof(string), false));
|
||||||
|
this.InputOptions.Add(new STNodeOption("SingleNode", typeof(System.Drawing.Image), true));
|
||||||
|
this.InputOptions.Add(new STNodeOption("SingleNode", typeof(object), true));
|
||||||
|
|
||||||
|
this.OutputOptions.Add(new STNodeOption("output", typeof(string), false));
|
||||||
|
this.OutputOptions.Add(new STNodeOption("Single", typeof(System.Drawing.Icon), true));
|
||||||
|
this.OutputOptions.Add(new STNodeOption("Single", typeof(object), true));
|
||||||
|
|
||||||
|
this.Title = "Demo_Node";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
WinNodeEditerTest/Demo_Image/FrmImage.Designer.cs
generated
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
namespace ST.Library.UI.Demo_Image
|
||||||
|
{
|
||||||
|
partial class FrmImage
|
||||||
|
{
|
||||||
|
/// <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.stNodeEditor1 = new ST.Library.UI.STNodeEditor();
|
||||||
|
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 = 1;
|
||||||
|
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 = 2;
|
||||||
|
this.button2.Text = "button2";
|
||||||
|
this.button2.UseVisualStyleBackColor = true;
|
||||||
|
this.button2.Click += new System.EventHandler(this.button2_Click);
|
||||||
|
//
|
||||||
|
// stNodeEditor1
|
||||||
|
//
|
||||||
|
this.stNodeEditor1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(34)))), ((int)(((byte)(34)))), ((int)(((byte)(34)))));
|
||||||
|
this.stNodeEditor1.Curvature = 0.3F;
|
||||||
|
this.stNodeEditor1.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.stNodeEditor1.LocationBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
|
||||||
|
this.stNodeEditor1.MarkBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
|
||||||
|
this.stNodeEditor1.MarkForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
|
||||||
|
this.stNodeEditor1.Name = "stNodeEditor1";
|
||||||
|
this.stNodeEditor1.Size = new System.Drawing.Size(200, 200);
|
||||||
|
this.stNodeEditor1.TabIndex = 0;
|
||||||
|
this.stNodeEditor1.Text = "stNodeEditor1";
|
||||||
|
//
|
||||||
|
// FrmImage
|
||||||
|
//
|
||||||
|
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.button2);
|
||||||
|
this.Controls.Add(this.button1);
|
||||||
|
this.Controls.Add(this.stNodeEditor1);
|
||||||
|
this.Name = "FrmImage";
|
||||||
|
this.Text = "FrmImage";
|
||||||
|
this.Load += new System.EventHandler(this.FrmImage_Load);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private STNodeEditor stNodeEditor1;
|
||||||
|
private System.Windows.Forms.Button button1;
|
||||||
|
private System.Windows.Forms.Button button2;
|
||||||
|
}
|
||||||
|
}
|
58
WinNodeEditerTest/Demo_Image/FrmImage.cs
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
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;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace ST.Library.UI.Demo_Image
|
||||||
|
{
|
||||||
|
public partial class FrmImage : Form
|
||||||
|
{
|
||||||
|
public FrmImage() {
|
||||||
|
InitializeComponent();
|
||||||
|
button1.Text = "Save";
|
||||||
|
button2.Text = "Open";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FrmImage_Load(object sender, EventArgs e) {
|
||||||
|
stNodeEditor1.Dock = DockStyle.Fill;
|
||||||
|
stNodeEditor1.TypeColor.Add(typeof(Image), Color.BlueViolet);
|
||||||
|
|
||||||
|
STNode node = new STNodeImageInput();
|
||||||
|
stNodeEditor1.Nodes.Add(node);
|
||||||
|
|
||||||
|
node = new STNodeImageChannel();
|
||||||
|
stNodeEditor1.Nodes.Add(node);
|
||||||
|
|
||||||
|
|
||||||
|
node = new STNodeImageChannel();
|
||||||
|
stNodeEditor1.Nodes.Add(node);
|
||||||
|
node = new STNodeImageChannel();
|
||||||
|
stNodeEditor1.Nodes.Add(node);
|
||||||
|
node = new STNodeImageChannel();
|
||||||
|
stNodeEditor1.Nodes.Add(node);
|
||||||
|
|
||||||
|
stNodeEditor1.LoadAssembly(Application.ExecutablePath);
|
||||||
|
stNodeEditor1.LoadAssembly(Directory.GetFiles("./", "*.dll"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button1_Click(object sender, EventArgs e) {
|
||||||
|
SaveFileDialog sfd = new SaveFileDialog();
|
||||||
|
sfd.Filter = "*.stn|*.stn";
|
||||||
|
if (sfd.ShowDialog() != DialogResult.OK) return;
|
||||||
|
stNodeEditor1.SaveCanvas(sfd.FileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button2_Click(object sender, EventArgs e) {
|
||||||
|
OpenFileDialog ofd = new OpenFileDialog();
|
||||||
|
ofd.Filter = "*.stn|*.stn";
|
||||||
|
if (ofd.ShowDialog() != DialogResult.OK) return;
|
||||||
|
stNodeEditor1.Nodes.Clear();
|
||||||
|
stNodeEditor1.LoadCanvas(ofd.FileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
WinNodeEditerTest/Demo_Image/FrmImage.resx
Executable 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>
|
52
WinNodeEditerTest/Demo_Image/STNodeImage.cs
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace ST.Library.UI.Demo_Image
|
||||||
|
{
|
||||||
|
public class STNodeImage : STNode
|
||||||
|
{
|
||||||
|
protected STNodeOption m_input_image; //输入输出点
|
||||||
|
protected STNodeOption m_out_image;
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
m_input_image = new STNodeOption("", typeof(Image), true);
|
||||||
|
this.InputOptions.Add(m_input_image);
|
||||||
|
m_out_image = new STNodeOption("", typeof(Image), false);
|
||||||
|
this.OutputOptions.Add(m_out_image);
|
||||||
|
m_input_image.DataTransfer += new STNodeOptionEventHandler(m_input_image_DataTransfer);
|
||||||
|
this.Title = "Image";
|
||||||
|
}
|
||||||
|
//监听输入点接入事件
|
||||||
|
void m_input_image_DataTransfer(object sender, STNodeOptionEventArgs e) {
|
||||||
|
if (e.Status != ConnectionStatus.Connected)
|
||||||
|
m_input_image.Data = null;
|
||||||
|
else
|
||||||
|
m_input_image.Data = e.TargetOption.Data;
|
||||||
|
m_out_image.TransferData(m_input_image.Data); //输出节点向下投递数据
|
||||||
|
this.OnDataTransfer(); //通知子类
|
||||||
|
this.Invalidate(); //重绘自己
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override System.Drawing.Size OnBuildNodeSize(DrawingTools dt) {
|
||||||
|
//return base.OnBuildNodeSize();
|
||||||
|
return new System.Drawing.Size(160, 120); //设定节点大小
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDrawBody(DrawingTools dt) { //重绘节点主体部分
|
||||||
|
base.OnDrawBody(dt);
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
|
||||||
|
if (m_input_image.Data != null) {
|
||||||
|
g.DrawImage((Image)m_input_image.Data, this.Left + 15, this.Top + 30, this.Width - 40, this.Height - 40);
|
||||||
|
} else {
|
||||||
|
g.FillRectangle(Brushes.Gray, this.Left + 15, this.Top + 30, this.Width - 40, this.Height - 40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnDataTransfer() { }
|
||||||
|
}
|
||||||
|
}
|
57
WinNodeEditerTest/Demo_Image/STNodeImageChannel.cs
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace ST.Library.UI.Demo_Image
|
||||||
|
{
|
||||||
|
public class STNodeImageChannel : STNodeImage
|
||||||
|
{
|
||||||
|
private STNodeOption m_out_r;
|
||||||
|
private STNodeOption m_out_g;
|
||||||
|
private STNodeOption m_out_b;
|
||||||
|
|
||||||
|
private Bitmap m_img_r;
|
||||||
|
private Bitmap m_img_g;
|
||||||
|
private Bitmap m_img_b;
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
m_out_r = new STNodeOption("R", typeof(Image), false);
|
||||||
|
m_out_g = new STNodeOption("G", typeof(Image), false);
|
||||||
|
m_out_b = new STNodeOption("B", typeof(Image), false);
|
||||||
|
this.OutputOptions.Add(m_out_r);
|
||||||
|
this.OutputOptions.Add(m_out_g);
|
||||||
|
this.OutputOptions.Add(m_out_b);
|
||||||
|
this.Title = "Channel";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDataTransfer() {
|
||||||
|
base.OnDataTransfer();
|
||||||
|
if (m_img_r != null) {
|
||||||
|
m_img_r.Dispose();
|
||||||
|
m_img_g.Dispose();
|
||||||
|
m_img_b.Dispose();
|
||||||
|
m_img_r = m_img_g = m_img_b = null;
|
||||||
|
}
|
||||||
|
if (m_out_image.Data != null) { //分离通道 Demo 演示 Get/SetPixel() 效率极低 应当LockBitmap操作
|
||||||
|
Bitmap img = (Bitmap)base.m_input_image.Data;
|
||||||
|
m_img_r = new Bitmap(img.Width, img.Height);
|
||||||
|
m_img_g = new Bitmap(img.Width, img.Height);
|
||||||
|
m_img_b = new Bitmap(img.Width, img.Height);
|
||||||
|
for (int x = 0; x < img.Width; x++) {
|
||||||
|
for (int y = 0; y < img.Height; y++) {
|
||||||
|
Color clr = img.GetPixel(x, y);
|
||||||
|
m_img_r.SetPixel(x, y, Color.FromArgb(255, clr.R, clr.R, clr.R));
|
||||||
|
m_img_g.SetPixel(x, y, Color.FromArgb(255, clr.G, clr.G, clr.G));
|
||||||
|
m_img_b.SetPixel(x, y, Color.FromArgb(255, clr.B, clr.B, clr.B));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_out_r.TransferData(m_img_r);
|
||||||
|
m_out_g.TransferData(m_img_b);
|
||||||
|
m_out_b.TransferData(m_img_b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
WinNodeEditerTest/Demo_Image/STNodeImageInput.cs
Executable file
@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace ST.Library.UI.Demo_Image
|
||||||
|
{
|
||||||
|
public class STNodeImageInput : STNode
|
||||||
|
{
|
||||||
|
private STNodeOption m_option_out;
|
||||||
|
|
||||||
|
private string m_str_file;
|
||||||
|
private Size m_sz = new Size(100, 60);
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
this.Title = "ImageInput";
|
||||||
|
m_option_out = new STNodeOption("", typeof(Image), false);
|
||||||
|
this.OutputOptions.Add(m_option_out);
|
||||||
|
STNodeButton btn = new STNodeButton();
|
||||||
|
btn.Left = (m_sz.Width - btn.Width) / 2;
|
||||||
|
btn.Top = (m_sz.Height - 20 - btn.Height) / 2;
|
||||||
|
btn.Text = "OpenImage";
|
||||||
|
btn.MouseClick += new MouseEventHandler(btn_MouseClick);
|
||||||
|
this.Controls.Add(btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void btn_MouseClick(object sender, MouseEventArgs e) {
|
||||||
|
OpenFileDialog ofd = new OpenFileDialog();
|
||||||
|
ofd.Filter = "*.jpg|*.jpg|*.png|*.png|*.bmp|*.bmp|*.*|*.*";
|
||||||
|
if (ofd.ShowDialog() != DialogResult.OK) return;
|
||||||
|
m_option_out.TransferData(Image.FromFile(ofd.FileName));
|
||||||
|
m_str_file = ofd.FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size OnBuildNodeSize(DrawingTools dt) {
|
||||||
|
//return base.OnBuildNodeSize();
|
||||||
|
return m_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Point OnSetOptionLocation(STNodeOption op) {
|
||||||
|
return new Point(op.DotLeft, this.Top + 35);
|
||||||
|
//return base.OnSetOptionLocation(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
//protected override void OnDrawOptionDot(DrawingTools dt, STNodeOption op) {
|
||||||
|
// //if (op == m_option_out) op.DotTop = this.Top + 35;
|
||||||
|
// base.OnDrawOptionDot(dt, op);
|
||||||
|
//}
|
||||||
|
|
||||||
|
protected override void OnSaveNode(Dictionary<string, byte[]> dic) {
|
||||||
|
if (m_str_file == null) m_str_file = string.Empty;
|
||||||
|
dic.Add("file", Encoding.UTF8.GetBytes(m_str_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnLoadNode(Dictionary<string, byte[]> dic) {
|
||||||
|
base.OnLoadNode(dic);
|
||||||
|
m_str_file = Encoding.UTF8.GetString(dic["file"]);
|
||||||
|
if (System.IO.File.Exists(m_str_file)) { //如果文件存在加载并投递数据
|
||||||
|
m_option_out.TransferData(Image.FromFile(m_str_file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class STNodeButton : STNodeControl //自定义一个Button控件
|
||||||
|
{
|
||||||
|
private bool m_isHover;
|
||||||
|
|
||||||
|
protected override void OnMouseEnter(EventArgs e) {
|
||||||
|
base.OnMouseEnter(e);
|
||||||
|
m_isHover = true;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseLeave(EventArgs e) {
|
||||||
|
base.OnMouseLeave(e);
|
||||||
|
m_isHover = false;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(DrawingTools dt) {
|
||||||
|
//base.OnPaint(dt);
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
SolidBrush brush = dt.SolidBrush;
|
||||||
|
brush.Color = m_isHover ? Color.DodgerBlue : this.BackColor;
|
||||||
|
g.FillRectangle(brush, 0, 0, this.Width, this.Height);
|
||||||
|
g.DrawString(this.Text, this.Font, Brushes.White, this.ClientRectangle, base.m_sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
WinNodeEditerTest/Form1.Designer.cs
generated
Executable file
@ -0,0 +1,100 @@
|
|||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
partial class Form1
|
||||||
|
{
|
||||||
|
/// <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.stNodeEditor1 = new ST.Library.UI.STNodeEditor();
|
||||||
|
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 = 4;
|
||||||
|
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 = 5;
|
||||||
|
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 = 6;
|
||||||
|
this.button3.Text = "button3";
|
||||||
|
this.button3.UseVisualStyleBackColor = true;
|
||||||
|
this.button3.Click += new System.EventHandler(this.button3_Click);
|
||||||
|
//
|
||||||
|
// stNodeEditor1
|
||||||
|
//
|
||||||
|
this.stNodeEditor1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(34)))), ((int)(((byte)(34)))), ((int)(((byte)(34)))));
|
||||||
|
this.stNodeEditor1.Curvature = 0.3F;
|
||||||
|
this.stNodeEditor1.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.stNodeEditor1.LocationBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
|
||||||
|
this.stNodeEditor1.MarkBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
|
||||||
|
this.stNodeEditor1.MarkForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
|
||||||
|
this.stNodeEditor1.Name = "stNodeEditor1";
|
||||||
|
this.stNodeEditor1.Size = new System.Drawing.Size(200, 200);
|
||||||
|
this.stNodeEditor1.TabIndex = 3;
|
||||||
|
this.stNodeEditor1.Text = "stNodeEditor1";
|
||||||
|
//
|
||||||
|
// Form1
|
||||||
|
//
|
||||||
|
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.button3);
|
||||||
|
this.Controls.Add(this.button2);
|
||||||
|
this.Controls.Add(this.button1);
|
||||||
|
this.Controls.Add(this.stNodeEditor1);
|
||||||
|
this.Name = "Form1";
|
||||||
|
this.Text = "Form1";
|
||||||
|
this.Load += new System.EventHandler(this.Form1_Load);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private STNodeEditor stNodeEditor1;
|
||||||
|
private System.Windows.Forms.Button button1;
|
||||||
|
private System.Windows.Forms.Button button2;
|
||||||
|
private System.Windows.Forms.Button button3;
|
||||||
|
}
|
||||||
|
}
|
87
WinNodeEditerTest/Form1.cs
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
using ST.Library.UI;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public partial class Form1 : Form
|
||||||
|
{
|
||||||
|
public Form1() {
|
||||||
|
InitializeComponent();
|
||||||
|
button1.Text = "Lock";
|
||||||
|
button2.Text = "Save";
|
||||||
|
button3.Text = "Open";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Form1_Load(object sender, EventArgs e) {
|
||||||
|
stNodeEditor1.Dock = DockStyle.Fill;
|
||||||
|
stNodeEditor1.TypeColor.Add(typeof(string), Color.Yellow);
|
||||||
|
stNodeEditor1.TypeColor.Add(typeof(Image), Color.Red);
|
||||||
|
|
||||||
|
stNodeEditor1.SelectedChanged += new EventHandler(stNodeEditor1_SelectedChanged);
|
||||||
|
stNodeEditor1.OptionConnected += new STNodeEditorOptionEventHandler(stNodeEditor1_OptionConnected);
|
||||||
|
stNodeEditor1.CanvasScaled += new EventHandler(stNodeEditor1_CanvasScaled);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
STNode node = new DemoNode();
|
||||||
|
//if (i == 2)
|
||||||
|
// node.Mark = "这里是标记信息\r\n\t新的一行数据";
|
||||||
|
//else
|
||||||
|
// node.Mark = "this is mark Info\r\nthis is new line " + i;
|
||||||
|
stNodeEditor1.Nodes.Add(node);
|
||||||
|
}
|
||||||
|
stNodeEditor1.Nodes.Add(new STNodeHub());
|
||||||
|
stNodeEditor1.Nodes.Add(new STNodeHub());
|
||||||
|
|
||||||
|
stNodeEditor1.Nodes.Add(new NodeNumberAdd());
|
||||||
|
|
||||||
|
stNodeEditor1.LoadAssembly(Application.ExecutablePath);
|
||||||
|
stNodeEditor1.LoadAssembly(Directory.GetFiles("./", "*.dll"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void stNodeEditor1_CanvasScaled(object sender, EventArgs e) {
|
||||||
|
stNodeEditor1.ShowAlert(stNodeEditor1.CanvasScale.ToString("F2"), Color.White, Color.Black);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stNodeEditor1_OptionConnected(object sender, STNodeEditorOptionEventArgs e) {
|
||||||
|
Console.WriteLine(e.CurrentOption.Text + " - " + e.TargetOption.Text + " - " + e.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stNodeEditor1_SelectedChanged(object sender, EventArgs e) {
|
||||||
|
foreach (var v in stNodeEditor1.GetSelectedNode()) {
|
||||||
|
Console.WriteLine("Selected - " + v.Title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button1_Click(object sender, EventArgs e) {
|
||||||
|
stNodeEditor1.Nodes[0].LockOption = !stNodeEditor1.Nodes[0].LockOption;
|
||||||
|
stNodeEditor1.Nodes[1].LockOption = !stNodeEditor1.Nodes[1].LockOption;
|
||||||
|
|
||||||
|
|
||||||
|
stNodeEditor1.Nodes[0].LockLocation = !stNodeEditor1.Nodes[0].LockLocation;
|
||||||
|
stNodeEditor1.Nodes[1].LockLocation = !stNodeEditor1.Nodes[1].LockLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button2_Click(object sender, EventArgs e) {
|
||||||
|
SaveFileDialog sfd = new SaveFileDialog();
|
||||||
|
sfd.Filter = "*.stn|*.stn";
|
||||||
|
if (sfd.ShowDialog() != DialogResult.OK) return;
|
||||||
|
stNodeEditor1.SaveCanvas(sfd.FileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button3_Click(object sender, EventArgs e) {
|
||||||
|
OpenFileDialog ofd = new OpenFileDialog();
|
||||||
|
ofd.Filter = "*.stn|*.stn";
|
||||||
|
if (ofd.ShowDialog() != DialogResult.OK) return;
|
||||||
|
stNodeEditor1.LoadCanvas(ofd.FileName);
|
||||||
|
stNodeEditor1.Nodes.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
WinNodeEditerTest/Form1.resx
Executable 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>
|
49
WinNodeEditerTest/NodeNumberAdd.cs
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
public class NodeNumberAdd : STNode
|
||||||
|
{
|
||||||
|
private STNodeOption m_in_num1;
|
||||||
|
private STNodeOption m_in_num2;
|
||||||
|
private STNodeOption m_out_num;
|
||||||
|
private int m_nNum1, m_nNum2;
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
this.Title = "NumberAdd";
|
||||||
|
m_in_num1 = new STNodeOption("num1", typeof(int), true);//只能有一个连线
|
||||||
|
m_in_num2 = new STNodeOption("num2", typeof(int), true);//只能有一个连线
|
||||||
|
m_out_num = new STNodeOption("result", typeof(int), false);//可以多个连线
|
||||||
|
this.InputOptions.Add(m_in_num1);
|
||||||
|
this.InputOptions.Add(m_in_num2);
|
||||||
|
this.OutputOptions.Add(m_out_num);
|
||||||
|
m_in_num1.DataTransfer += new STNodeOptionEventHandler(m_in_num_DataTransfer);
|
||||||
|
m_in_num2.DataTransfer += new STNodeOptionEventHandler(m_in_num_DataTransfer);
|
||||||
|
}
|
||||||
|
//当有数据传入时
|
||||||
|
void m_in_num_DataTransfer(object sender, STNodeOptionEventArgs e) {
|
||||||
|
//判断连线是否是连接状态(建立连线 断开连线 都会触发该事件)
|
||||||
|
if (e.Status == ConnectionStatus.Connected) {
|
||||||
|
if (sender == m_in_num1)
|
||||||
|
m_nNum1 = (int)e.TargetOption.Data;//TargetOption为触发此事件的Option
|
||||||
|
else
|
||||||
|
m_nNum2 = (int)e.TargetOption.Data;
|
||||||
|
} else {
|
||||||
|
if (sender == m_in_num1) m_nNum1 = 0; else m_nNum2 = 0;
|
||||||
|
}
|
||||||
|
//向输出选项上的所有连线传输数据 输出选项上的所有连线都会触发 DataTransfer 事件
|
||||||
|
m_out_num.TransferData(m_nNum1 + m_nNum2); //m_out_num.Data 将被自动设置
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnOwnerChanged() {
|
||||||
|
base.OnOwnerChanged();//通常刚被添加到节点编辑器时触发 如是以插件方式提供的节点 应当向编辑器提交数据类型颜色
|
||||||
|
if (this.Owner == null) return; //或者通过m_in_num1.DotColor = Color.Red;进行设置
|
||||||
|
this.Owner.SetTypeColor(typeof(int), Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
WinNodeEditerTest/Program.cs
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace ST.Library.UI
|
||||||
|
{
|
||||||
|
static class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
static void Main() {
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
new Demo_Image.FrmImage().Show();
|
||||||
|
Application.Run(new Form1());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
WinNodeEditerTest/Properties/AssemblyInfo.cs
Executable file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("WinNodeEditerTest")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("Microsoft")]
|
||||||
|
[assembly: AssemblyProduct("WinNodeEditerTest")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © Microsoft 2020")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("2c0c84a0-fb66-4133-80f5-053356fa0f04")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
63
WinNodeEditerTest/Properties/Resources.Designer.cs
generated
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace ST.Library.UI.Properties {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ST.Library.UI.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
117
WinNodeEditerTest/Properties/Resources.resx
Executable file
@ -0,0 +1,117 @@
|
|||||||
|
<?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.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: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" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</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" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</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=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
26
WinNodeEditerTest/Properties/Settings.Designer.cs
generated
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace ST.Library.UI.Properties {
|
||||||
|
|
||||||
|
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default {
|
||||||
|
get {
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
WinNodeEditerTest/Properties/Settings.settings
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
111
WinNodeEditerTest/WinNodeEditerTest.csproj
Executable file
@ -0,0 +1,111 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{8B0A4516-45C9-4DE9-B947-64E8DA8A72A6}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>ST.Library.UI</RootNamespace>
|
||||||
|
<AssemblyName>WinNodeEditerTest</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<StartupObject />
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Deployment" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="DemoNode.cs" />
|
||||||
|
<Compile Include="Demo_Image\FrmImage.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Demo_Image\FrmImage.Designer.cs">
|
||||||
|
<DependentUpon>FrmImage.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Demo_Image\STNodeImage.cs" />
|
||||||
|
<Compile Include="Demo_Image\STNodeImageChannel.cs" />
|
||||||
|
<Compile Include="Demo_Image\STNodeImageInput.cs" />
|
||||||
|
<Compile Include="Form1.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Form1.Designer.cs">
|
||||||
|
<DependentUpon>Form1.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="NodeNumberAdd.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<EmbeddedResource Include="Demo_Image\FrmImage.resx">
|
||||||
|
<DependentUpon>FrmImage.cs</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Form1.resx">
|
||||||
|
<DependentUpon>Form1.cs</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
</Compile>
|
||||||
|
<None Include="app.config" />
|
||||||
|
<None Include="Properties\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
<Compile Include="Properties\Settings.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ST.Library.UI\ST.Library.UI.csproj">
|
||||||
|
<Project>{EFFCC270-4999-4077-A543-56CCCCE92147}</Project>
|
||||||
|
<Name>ST.Library.UI</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
3
WinNodeEditerTest/app.config
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<configuration>
|
||||||
|
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
|