Field&Property
/// <summary>
/// GraphWindow
/// </summary>
private GraphWindow m_GraphWindow;
/// <summary>
/// Node搜索窗口
/// </summary>
private SearchWindowProvider m_SearchWindow;
/// <summary>
/// 每个Node的NodeView
/// </summary>
public Dictionary<Node, NodeView> nodeViewsPerNode = new Dictionary<Node, NodeView>();
/// <summary>
/// Graph
/// </summary>
public Graph graph { get { return m_GraphWindow.graph; } }
public GraphView()
{
viewTransformChanged += ViewTransformChangedCallback;
graphViewChanged += GraphViewChangedCallback;
AddManipulators();
InitializeView();
Undo.undoRedoPerformed += Reload;
}
~GraphView()
{
Undo.undoRedoPerformed -= Reload;
}
Method
AddManipulators
/// <summary>
/// 添加鼠标操作到窗口
/// </summary>
private void AddManipulators()
{
this.AddManipulator(new ContentDragger());
this.AddManipulator(new SelectionDragger());
this.AddManipulator(new RectangleSelector());
this.AddManipulator(new ClickSelector());
}
InitializeView
/// <summary>
/// 初始化窗口
/// </summary>
private void InitializeView()
{
//加载USS文件
this.styleSheets.Add(Resources.Load<StyleSheet>("GraphView"));
//网格背景
GridBackground gridBackground = new GridBackground();
gridBackground.name = "GridBackground";
Insert(0, gridBackground);
//设施缩放的范围
this.SetupZoom(0.5f, 2.0f);
//填充整个窗口
this.StretchToParentSize();
//添加创建Node搜索窗口
m_SearchWindow = new SearchWindowProvider();
m_SearchWindow.OnSelect = OnSelect;
nodeCreationRequest = (NodeCreationContext context) =>
{ SearchWindow.Open(new SearchWindowContext(context.screenMousePosition), m_SearchWindow); };
}
Initialize
/// <summary>
/// 初始化Graph
/// </summary>
/// <param name="graphWindow"></param>
public void Initialize(GraphWindow graphWindow)
{
m_GraphWindow = graphWindow;
UpdateViewTransform(graph.position, graph.scale);
Reload();
}
Reload
/// <summary>
/// 重新绘制用于撤销回调
/// </summary>
public void Reload()
{
Debug.Log("Reload");
RemoveNodeView();
RemovePortView();
InitializeNodeView();
InitializePortView();
}
RemoveNodeView
/// <summary>
/// 移除所有NodeView
/// </summary>
public void RemoveNodeView()
{
foreach (var node in nodeViewsPerNode)
{
NodeView nodeView = node.Value;
nodeView.OnRemove();
RemoveElement(nodeView);
}
nodeViewsPerNode.Clear();
}
RemovePortView
/// <summary>
/// 移除所有NodeView
/// </summary>
public void RemovePortView()
{
var edges = this.edges;
edges.ForEach((edge) =>
{
RemoveElement(edge);
});
}
InitializeNodeView
/// <summary>
/// 初始化所有NodeView
/// </summary>
public void InitializeNodeView()
{
var nodes = graph.GetComponentsInChildren<Node>();
foreach (var node in nodes)
{
var nodeView = AddNodeView(node, node.position);
nodeView.Initialize(node, this);
nodeViewsPerNode.Add(node, nodeView);
}
}
InitializePortView
/// <summary>
/// 初始化所有PortView
/// </summary>
public void InitializePortView()
{
foreach (var node in nodeViewsPerNode)
{
node.Value.InitializePortView();
}
}
OnSelect
/// <summary>
/// 当选择创建Node时
/// </summary>
/// <param name="SearchTreeEntry"></param>
/// <param name="context"></param>
/// <returns></returns>
private bool OnSelect(SearchTreeEntry SearchTreeEntry, SearchWindowContext context)
{
var node = AddNode(SearchTreeEntry.userData as Type);
var windowRoot = m_GraphWindow.rootVisualElement;
var windowMousePosition = windowRoot.ChangeCoordinatesTo(windowRoot.parent, context.screenMousePosition - m_GraphWindow.position.position);
var graphMousePosition = this.contentViewContainer.WorldToLocal(windowMousePosition);
var nodeView = AddNodeView(node, graphMousePosition);
nodeViewsPerNode.Add(node, nodeView);
return true;
}
AddNode
/// <summary>
/// 添加Node
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
Node AddNode(Type type)
{
var obj = new GameObject(type.Name);
Undo.RegisterCreatedObjectUndo(obj, $"Create:{obj.name}");
var component = obj.AddComponent(type);
obj.transform.parent = graph.transform;
return component as Node;
}
AddNodeView
/// <summary>
/// 添加NodeView
/// </summary>
/// <param name="node"></param>
/// <param name="pos"></param>
/// <returns></returns>
NodeView AddNodeView(Node node, Vector2 pos)
{
Type nodeViewType = m_SearchWindow.GetNodeView(node.GetType());
var nodeView = System.Activator.CreateInstance(nodeViewType) as NodeView;
nodeView.Initialize(node, this);
nodeView.SetPosition(new Rect(pos, new Vector2(100, 100)));
nodeView.RefreshPorts();
nodeView.RefreshExpandedState();
AddElement(nodeView);
return nodeView;
}
GetCompatiblePorts
/// <summary>
/// 当选择Port是返回所有可以连接的Port
/// </summary>
/// <param name="startPort"></param>
/// <param name="nodeAdapter"></param>
/// <returns></returns>
public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
{
return base.GetCompatiblePorts(startPort, nodeAdapter);
}
ViewTransformChangedCallback
/// <summary>
/// 移动缩放回调
/// </summary>
/// <param name="graphView"></param>
private void ViewTransformChangedCallback(GraphViewBase graphView)
{
Undo.RecordObject(graph, $"{graph.name} Transform Change");
graph.position = graphView.viewTransform.position;
graph.scale = graphView.viewTransform.scale;
EditorUtility.SetDirty(graph);
}
GraphViewChangedCallback
/// <summary>
/// 当界面变化是回调
/// </summary>
/// <param name="graphViewChange"></param>
/// <returns></returns>
private GraphViewChange GraphViewChangedCallback(GraphViewChange graphViewChange)
{
return graphViewChange;
}
BuildContextualMenu
/// <summary>
/// 添加右键菜单事件
/// </summary>
/// <param name="evt"></param>
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
base.BuildContextualMenu(evt);
evt.menu.AppendAction("Test", TestBuildContextualMenu);
}
/// <summary>
/// 右键菜单Test
/// </summary>
/// <param name="obj"></param>
private void TestBuildContextualMenu(DropdownMenuAction obj)
{
Debug.Log("右键菜单Test");
}