本篇我们将实现表达式编辑器的UI功能部分
0 操作数节点FloatNode
既然我们的目标是实现一个逻辑表达式,我们需要一个FloatNode作为基本的操作数。你也可以实现自己的Int版本
我们在Node的ContentContainer中加入FloatField输入框让用户输入内容
`
public class YaoJZFloatNodeView:Node
{
private FloatField _floatField;
public Port OutputPort;
public YaoJZFloatNodeView()
{
title = "Float";
OutputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Single, typeof(Port));
outputContainer.Add(OutputPort);
_floatField = new FloatField(); //添加一个floatfield输入框
_floatField.RegisterValueChangedCallback(OnFloatValueChanged);
contentContainer.Add(_floatField);
RefreshExpandedState();
}
private void OnFloatValueChanged(ChangeEvent<float> evt)
{
//输入内容变化了
}
public float Value
{
get{return _floatField.value;}
set { _floatField.value = value; }
}
}
`
1 BinaryOpNode二元操作节点
现在我们实现一个二元操作功能的Node,这个Node实现二院表达式,我们先实现数学运算的加减乘除
BinaryOpNode有2个输入Port,分别来连接左操作数节点和右操作数节点
另外需要一个Output的Port,代表操作后的结果输出
public class YaoJZBinaryOpNodeView:Node
{
public Port LeftInput; //左操作数节点端口
public Port RightInput; //右操作数节点端口
public Port OutputPort;
public YaoJZBinaryOpNodeView()
{
this.title = "BinaryOp";
OutputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Single, typeof(Port));
outputContainer.Add(OutputPort);
LeftInput = Port.Create<Edge>(Orientation.Horizontal, Direction.Input, Port.Capacity.Single, typeof(Port));
inputContainer.Add(LeftInput);
RightInput = Port.Create<Edge>(Orientation.Horizontal, Direction.Input, Port.Capacity.Single, typeof(Port));
inputContainer.Add(RightInput);
}
}
`
我们需要定义一个操作方法枚举,代表我们可以进行的操作行为类型
public enum BinaryNodeOpType
{
Add,
Sub,
Divide,
Mutiply,
}
然后我们添加一个EnumField,让用户可以在Node中选择自己想要的BinaryNodeOpType
YaoJZBinaryOpNodeView.cs类
public class YaoJZBinaryOpNodeView:Node
{
private EnumField _opEnumField;
public Enums.BinaryNodeOpType OpType
{
get { return (Enums.BinaryNodeOpType)_opEnumField.value; }
set { _opEnumField.value = value; }
}
public YaoJZBinaryOpNodeView()
{
//...之前的代码
_opEnumField = new EnumField();
_opEnumField.Init(Enums.BinaryNodeOpType.Add);
contentContainer.Add(_opEnumField);
}
}
别忘了将节点添加到ISearchWindowProvider的右键菜单中
public class YaoJZSearchMenuWindowProvider:ScriptableObject, ISearchWindowProvider
{
public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
{
var entries = new List<SearchTreeEntry>();
entries.Add(new SearchTreeGroupEntry(new GUIContent("Create Node")));
entries.Add(new SearchTreeGroupEntry(new GUIContent("Example")) { level = 1 });
entries.Add(new SearchTreeEntry(new GUIContent("float")) { level = 2, userData = typeof(YaoJZFloatNodeView) });
entries.Add(new SearchTreeEntry(new GUIContent("binary")) { level = 2, userData = typeof(YaoJZBinaryOpNodeView) });
return entries;
}
}
改进:每次添加新节点未免有些麻烦,我们可以通过Attribute功能,利用反射将节点添加到右键菜单中。
现在我们连接一下看看最终的效果
我们的表达式编辑器的UI部分已经实现的差不多了,下一篇我们实现表达式的运行时逻辑