您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

328 行
13 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using RMGUI.GraphView;
using UnityEditor.Graphing.Util;
using UnityEngine;
using UnityEngine.Graphing;
namespace UnityEditor.Graphing.Drawing
{
[Serializable]
public abstract class AbstractGraphPresenter : GraphViewPresenter
{
protected GraphTypeMapper typeMapper { get; set; }
public IGraphAsset graphAsset { get; private set; }
[SerializeField]
private TitleBarPresenter m_TitleBar;
[SerializeField]
private EditorWindow m_Container;
public TitleBarPresenter titleBar
{
get { return m_TitleBar; }
}
protected AbstractGraphPresenter()
{
typeMapper = new GraphTypeMapper(typeof(GraphNodePresenter));
}
void OnNodeChanged(INode inNode, ModificationScope scope)
{
var dependentNodes = new List<INode>();
NodeUtils.CollectNodesNodeFeedsInto(dependentNodes, inNode);
foreach (var node in dependentNodes)
{
var theElements = m_Elements.OfType<GraphNodePresenter>().ToList();
var found = theElements.Where(x => x.node.guid == node.guid).ToList();
foreach (var drawableNodeData in found)
drawableNodeData.OnModified(scope);
}
if (scope == ModificationScope.Topological)
UpdateData();
EditorUtility.SetDirty(graphAsset.GetScriptableObject());
if (m_Container != null)
m_Container.Repaint();
}
private void UpdateData()
{
// Find all nodes currently being drawn which are no longer in the graph (i.e. deleted)
var deletedElements = m_Elements
.OfType<GraphNodePresenter>()
.Where(nd => !graphAsset.graph.GetNodes<INode>().Contains(nd.node))
.OfType<GraphElementPresenter>()
.ToList();
var deletedEdges = m_Elements.OfType<GraphEdgePresenter>()
.Where(ed => !graphAsset.graph.edges.Contains(ed.edge));
// Find all edges currently being drawn which are no longer in the graph (i.e. deleted)
foreach (var edgeData in deletedEdges)
{
// Make sure to disconnect the node, otherwise new connections won't be allowed for the used slots
edgeData.output.Disconnect(edgeData);
edgeData.input.Disconnect(edgeData);
var toNodeGuid = edgeData.edge.inputSlot.nodeGuid;
var toNode = m_Elements.OfType<GraphNodePresenter>().FirstOrDefault(nd => nd.node.guid == toNodeGuid);
if (toNode != null)
{
// Make the input node (i.e. right side of the connection) re-render
OnNodeChanged(toNode.node, ModificationScope.Graph);
}
deletedElements.Add(edgeData);
}
// Remove all nodes and edges marked for deletion
foreach (var deletedElement in deletedElements)
{
m_Elements.Remove(deletedElement);
}
var addedNodes = new List<GraphNodePresenter>();
// Find all new nodes and mark for addition
foreach (var node in graphAsset.graph.GetNodes<INode>())
{
// Check whether node already exists
if (m_Elements.OfType<GraphNodePresenter>().Any(e => e.node == node))
continue;
var nodeData = (GraphNodePresenter)typeMapper.Create(node);
node.onModified += OnNodeChanged;
nodeData.Initialize(node);
addedNodes.Add(nodeData);
}
// Create edge data for nodes marked for addition
var drawableEdges = new List<GraphEdgePresenter>();
foreach (var addedNode in addedNodes)
{
var baseNode = addedNode.node;
foreach (var slot in baseNode.GetOutputSlots<ISlot>())
{
var sourceAnchors = addedNode.elements.OfType<GraphAnchorPresenter>();
var sourceAnchor = sourceAnchors.FirstOrDefault(x => x.slot == slot);
var edges = baseNode.owner.GetEdges(new SlotReference(baseNode.guid, slot.id));
foreach (var edge in edges)
{
var toNode = baseNode.owner.GetNodeFromGuid(edge.inputSlot.nodeGuid);
var toSlot = toNode.FindInputSlot<ISlot>(edge.inputSlot.slotId);
var targetNode = addedNodes.FirstOrDefault(x => x.node == toNode);
var targetAnchors = targetNode.elements.OfType<GraphAnchorPresenter>();
var targetAnchor = targetAnchors.FirstOrDefault(x => x.slot == toSlot);
var edgeData = CreateInstance<GraphEdgePresenter>();
edgeData.Initialize(edge);
edgeData.output = sourceAnchor;
edgeData.output.Connect(edgeData);
edgeData.input = targetAnchor;
edgeData.input.Connect(edgeData);
drawableEdges.Add(edgeData);
}
}
}
// Add nodes marked for addition
m_Elements.AddRange(addedNodes.OfType<GraphElementPresenter>());
// Find edges in the graph that are not being drawn and create edge data for them
foreach (var edge in graphAsset.graph.edges)
{
if (!m_Elements.OfType<GraphEdgePresenter>().Any(ed => ed.edge == edge))
{
var fromNode = graphAsset.graph.GetNodeFromGuid(edge.outputSlot.nodeGuid);
var fromSlot = fromNode.FindOutputSlot<ISlot>(edge.outputSlot.slotId);
var sourceNode = m_Elements.OfType<GraphNodePresenter>().FirstOrDefault(x => x.node == fromNode);
var sourceAnchors = sourceNode.elements.OfType<GraphAnchorPresenter>();
var sourceAnchor = sourceAnchors.FirstOrDefault(x => x.slot == fromSlot);
var toNode = graphAsset.graph.GetNodeFromGuid(edge.inputSlot.nodeGuid);
var toSlot = toNode.FindInputSlot<ISlot>(edge.inputSlot.slotId);
var targetNode = m_Elements.OfType<GraphNodePresenter>().FirstOrDefault(x => x.node == toNode);
var targetAnchors = targetNode.elements.OfType<GraphAnchorPresenter>();
var targetAnchor = targetAnchors.FirstOrDefault(x => x.slot == toSlot);
OnNodeChanged(targetNode.node, ModificationScope.Graph);
var edgeData = CreateInstance<GraphEdgePresenter>();
edgeData.Initialize(edge);
edgeData.output = sourceAnchor;
edgeData.output.Connect(edgeData);
edgeData.input = targetAnchor;
edgeData.input.Connect(edgeData);
drawableEdges.Add(edgeData);
}
}
m_Elements.AddRange(drawableEdges.OfType<GraphElementPresenter>());
}
public virtual void Initialize(IGraphAsset graphAsset, AbstractGraphEditWindow container)
{
this.graphAsset = graphAsset;
m_Container = container;
m_TitleBar = CreateInstance<TitleBarPresenter>();
m_TitleBar.Initialize(container);
if (graphAsset == null)
return;
UpdateData();
}
public void AddNode(INode node)
{
graphAsset.graph.AddNode(node);
EditorUtility.SetDirty(graphAsset.GetScriptableObject());
UpdateData();
}
public void RemoveElements(IEnumerable<GraphNodePresenter> nodes, IEnumerable<GraphEdgePresenter> edges)
{
graphAsset.graph.RemoveElements(nodes.Select(x => x.node), edges.Select(x => x.edge));
graphAsset.graph.ValidateGraph();
EditorUtility.SetDirty(graphAsset.GetScriptableObject());
UpdateData();
}
public void Connect(GraphAnchorPresenter left, GraphAnchorPresenter right)
{
if (left != null && right != null)
{
graphAsset.graph.Connect(left.slot.slotReference, right.slot.slotReference);
EditorUtility.SetDirty(graphAsset.GetScriptableObject());
UpdateData();
}
}
private CopyPasteGraph CreateCopyPasteGraph(IEnumerable<GraphElementPresenter> selection)
{
var graph = new CopyPasteGraph();
foreach (var presenter in selection)
{
var nodePresenter = presenter as GraphNodePresenter;
if (nodePresenter != null)
{
graph.AddNode(nodePresenter.node);
foreach (var edge in NodeUtils.GetAllEdges(nodePresenter.node))
graph.AddEdge(edge);
}
var edgePresenter = presenter as GraphEdgePresenter;
if (edgePresenter != null)
graph.AddEdge(edgePresenter.edge);
}
return graph;
}
private CopyPasteGraph DeserializeCopyBuffer(string copyBuffer)
{
try
{
return JsonUtility.FromJson<CopyPasteGraph>(copyBuffer);
}
catch
{
// ignored. just means copy buffer was not a graph :(
return null;
}
}
private void InsertCopyPasteGraph(CopyPasteGraph graph)
{
if (graph == null || graphAsset == null || graphAsset.graph == null)
return;
var addedNodes = new List<INode>();
var nodeGuidMap = new Dictionary<Guid, Guid>();
foreach (var node in graph.GetNodes<INode>())
{
var oldGuid = node.guid;
var newGuid = node.RewriteGuid();
nodeGuidMap[oldGuid] = newGuid;
var drawState = node.drawState;
var position = drawState.position;
position.x += 30;
position.y += 30;
drawState.position = position;
node.drawState = drawState;
graphAsset.graph.AddNode(node);
addedNodes.Add(node);
}
// only connect edges within pasted elements, discard
// external edges.
var addedEdges = new List<IEdge>();
foreach (var edge in graph.edges)
{
var outputSlot = edge.outputSlot;
var inputSlot = edge.inputSlot;
Guid remappedOutputNodeGuid;
Guid remappedInputNodeGuid;
if (nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid)
&& nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid))
{
var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId);
var inputSlotRef = new SlotReference(remappedInputNodeGuid, inputSlot.slotId);
addedEdges.Add(graphAsset.graph.Connect(outputSlotRef, inputSlotRef));
}
}
graphAsset.graph.ValidateGraph();
UpdateData();
graphAsset.drawingData.selection = addedNodes.Select(n => n.guid);
}
public void Copy(IEnumerable<GraphElementPresenter> selection)
{
var graph = CreateCopyPasteGraph(selection);
EditorGUIUtility.systemCopyBuffer = JsonUtility.ToJson(graph, true);
}
public void Duplicate(IEnumerable<GraphElementPresenter> selection)
{
var graph = DeserializeCopyBuffer(JsonUtility.ToJson(CreateCopyPasteGraph(selection), true));
InsertCopyPasteGraph(graph);
}
public void Paste()
{
var pastedGraph = DeserializeCopyBuffer(EditorGUIUtility.systemCopyBuffer);
InsertCopyPasteGraph(pastedGraph);
}
public override void AddElement(EdgePresenter edge)
{
Connect(edge.output as GraphAnchorPresenter, edge.input as GraphAnchorPresenter);
}
public override void AddElement(GraphElementPresenter element)
{
throw new ArgumentException("Not supported on Serializable Graph, data comes from data store");
}
public override void RemoveElement(GraphElementPresenter element)
{
throw new ArgumentException("Not supported on Serializable Graph, data comes from data store");
}
}
}