public static PortView Create( Port port, Type type, IEdgeConnectorListener connectorListener ) { if (type == null) { Debug.Log($"Port {port.name} has null type"); } var view = new PortView( Orientation.Horizontal, port.isInput ? Direction.Input : Direction.Output, port.acceptsMultipleConnections ? Capacity.Multi : Capacity.Single, type ) { m_EdgeConnector = new EdgeConnector <Edge>(connectorListener), portName = port.name, target = port }; // Override default connector text with the human-readable port name // TODO: Apparently the edge connector (Edge.output.portName) is based on whatever // is in this label. So re-labeling it will inadvertedly change the port name. // (or it might be a two way binding). So natively, we won't be able to have multiple // ports with the same name. // view.m_ConnectorText.text = refPort.displayName; view.AddManipulator(view.m_EdgeConnector); return(view); }
protected virtual void AddInputPort(Port port) { var view = PortView.Create(port, port.type, m_ConnectorListener); // If we want to display an inline editable field as part // of the port, create a new PropertyField and bind it. if (port.fieldName != null) { var prop = m_SerializedNode.FindPropertyRelative(port.fieldName); if (prop != null) { var field = new PropertyField(prop, " "); field.Bind(m_SerializedNode.serializedObject); field.RegisterCallback((FocusOutEvent e) => OnPropertyChange()); var container = new VisualElement(); container.AddToClassList("property-field-container"); container.Add(field); view.SetEditorField(container); } } inputs.Add(view); inputContainer.Add(view); }
protected virtual void AddOutputPort(Port port) { var view = PortView.Create(port, ConnectorListener); Outputs.Add(view); outputContainer.Add(view); }
/// <summary> /// Create a new node from reflection data and insert into the Graph. /// </summary> internal void AddNodeFromSearch(Node node, Vector2 screenPosition, PortView connectedPort = null, bool registerUndo = true) { // Calculate where to place this node on the graph var windowRoot = EditorWindow.rootVisualElement; var windowMousePosition = EditorWindow.rootVisualElement.ChangeCoordinatesTo( windowRoot.parent, screenPosition - EditorWindow.position.position ); var graphMousePosition = contentViewContainer.WorldToLocal(windowMousePosition); // Track undo and add to the graph if (registerUndo) { Undo.RegisterCompleteObjectUndo(Graph, $"Add Node {node.Name}"); } node.Position = graphMousePosition; Graph.AddNode(node); serializedGraph.Update(); EditorUtility.SetDirty(Graph); // Add a node to the visual graph var editorType = NodeReflection.GetNodeEditorType(node.GetType()); var element = Activator.CreateInstance(editorType) as NodeView; element.Initialize(node, this, edgeConnectorListener); AddElement(element); // If there was a provided existing port to connect to, find the best // candidate port on the new node and connect. if (connectedPort != null) { var edge = new GraphViewEdge(); if (connectedPort.direction == Direction.Input) { edge.input = connectedPort; edge.output = element.GetCompatibleOutputPort(connectedPort); } else { edge.output = connectedPort; edge.input = element.GetCompatibleInputPort(connectedPort); } AddEdge(edge, false); } Dirty(element); }
/// <summary> /// Return true if this port can be connected with an edge to the given port /// </summary> public bool IsCompatibleWith(PortView other) { if (other.node == node || other.direction == direction) { return(false); } // TODO: Loop detection to ensure nobody is making a cycle // (for certain use cases, that is) // Check for type cast support in the direction of output port -> input port return((other.direction == Direction.Input && portType.IsCastableTo(other.portType, true)) || (other.direction == Direction.Output && other.portType.IsCastableTo(portType, true))); }
public static PortView Create(Port port, IEdgeConnectorListener connectorListener) { Direction direction = port.Direction == PortDirection.Input ? Direction.Input : Direction.Output; Capacity capacity = port.Capacity == PortCapacity.Multiple ? Capacity.Multi : Capacity.Single; var view = new PortView(Orientation.Horizontal, direction, capacity, port.Type) { m_EdgeConnector = new EdgeConnector <Edge>(connectorListener), portName = port.Name, Target = port }; view.AddManipulator(view.m_EdgeConnector); return(view); }
protected virtual void AddInputPort(Port port) { var view = PortView.Create(port, ConnectorListener); // If we're exposing a control element via reflection: include it in the view var reflection = NodeReflection.GetNodeType(Target.GetType()); var element = reflection.GetPortByName(port.Name)?.GetControlElement(this); if (element != null) { var container = new VisualElement(); container.AddToClassList("property-field-container"); container.Add(element); view.SetEditorField(container); } Inputs.Add(view); inputContainer.Add(view); }
public PortView GetCompatibleOutputPort(PortView input) { return(Outputs.Find((port) => port.IsCompatibleWith(input))); }
public PortView GetCompatibleInputPort(PortView output) { return(Inputs.Find((port) => port.IsCompatibleWith(output))); }
public void OpenSearch(Vector2 screenPosition, PortView connectedPort = null) { searchWindow.SourcePort = connectedPort; GraphViewSearchWindow.Open(new SearchWindowContext(screenPosition), searchWindow); }
public void OpenSearch(Vector2 screenPosition, PortView connectedPort = null) { m_SearchProvider.sourcePort = connectedPort; SearchWindow.Open(new SearchWindowContext(screenPosition), m_SearchProvider); }
/// <summary> /// Create a new node from reflection data and insert into the Graph. /// </summary> internal void AddNodeFromReflectionData( NodeReflectionData data, Vector2 screenPosition, PortView connectedPort = null ) { // Calculate where to place this node on the graph var windowRoot = m_EditorWindow.rootVisualElement; var windowMousePosition = m_EditorWindow.rootVisualElement.ChangeCoordinatesTo( windowRoot.parent, screenPosition - m_EditorWindow.position.position ); var graphMousePosition = contentViewContainer.WorldToLocal(windowMousePosition); // Create a new node instance and set initial data (ports, etc) Undo.RegisterCompleteObjectUndo(m_Graph, $"Add Node {data.name}"); Debug.Log($"+node {data.name}"); var node = data.CreateInstance(); node.graphPosition = graphMousePosition; m_Graph.AddNode(node); m_SerializedGraph.Update(); EditorUtility.SetDirty(m_Graph); var serializedNodesArr = m_SerializedGraph.FindProperty("nodes"); var nodeIdx = m_Graph.nodes.IndexOf(node); var serializedNode = serializedNodesArr.GetArrayElementAtIndex(nodeIdx); // Add a node to the visual graph var editorType = NodeReflection.GetNodeEditorType(data.type); var element = Activator.CreateInstance(editorType) as NodeView; element.Initialize(node, serializedNode, m_EdgeListener); AddElement(element); // If there was a provided existing port to connect to, find the best // candidate port on the new node and connect. if (connectedPort != null) { var edge = new Edge(); if (connectedPort.direction == Direction.Input) { edge.input = connectedPort; edge.output = element.GetCompatibleOutputPort(connectedPort); } else { edge.output = connectedPort; edge.input = element.GetCompatibleInputPort(connectedPort); } AddEdge(edge, false); } Dirty(element); }
private VisualElement AddItem(string property_path, int index) { var port_name = $"{this.list_name}[{index}]"; var port = parent_node.GetPort(port_name); var prop = m_SerializedList.GetArrayElementAtIndex(index); if (port == null) { Debug.Log("Added port!"); port = new Port { name = port_name, isInput = false, acceptsMultipleConnections = false, type = list_type, fieldName = prop.propertyPath }; parent_node.AddPort(port); m_SerializedList.serializedObject.Update(); } var view = PortView.Create(port, port.type, m_ConnectorListener); view.hideEditorFieldOnConnection = false; var field = new PropertyField(prop, ""); field.Bind(m_SerializedList.serializedObject); field.RegisterCallback((FocusOutEvent e) => m_OnPropertyChange()); var container = new VisualElement(); container.AddToClassList("property-field-container"); container.style.flexDirection = FlexDirection.Row; var remove_button = new Button(() => { m_UpdateBinding(); m_SerializedList.DeleteArrayElementAtIndex(index); m_SerializedList.serializedObject.ApplyModifiedProperties(); m_UpdateBinding(); int new_size = m_SerializedList.arraySize; var canvas = GetFirstAncestorOfType <CanvasView>(); var connections = new List <Edge>(items[index].connections); foreach (var connection in connections) { canvas.RemoveEdge(connection, false); } for (int i = index; i < new_size; i++) { connections = new List <Edge>(items[i + 1].connections); foreach (Edge connection in connections) { var connect_to = connection.input; canvas.RemoveEdge(connection, false); if (connect_to != null) { canvas.AddEdge(new Edge { input = connect_to, output = items[i] }, false); } } } canvas.DirtyAll(); // Remove the last port from the list! parent_node.RemovePort(parent_node.GetPort($"{list_name}[{new_size}]")); m_SerializedList.serializedObject.Update(); m_UpdateBinding(); m_OnPropertyChange(); }); remove_button.text = "-"; remove_button.style.color = new StyleColor(UnityEngine.Color.white); remove_button.style.backgroundColor = new StyleColor(UnityEngine.Color.red); remove_button.style.marginBottom = new StyleLength(0.0); remove_button.style.marginLeft = new StyleLength(0.0); remove_button.style.marginTop = new StyleLength(0.0); remove_button.style.marginRight = new StyleLength(0.0); remove_button.style.borderBottomLeftRadius = new StyleLength(0.0); remove_button.style.borderTopLeftRadius = new StyleLength(0.0); remove_button.style.borderTopRightRadius = new StyleLength(0.0); remove_button.style.borderBottomRightRadius = new StyleLength(0.0); container.Add(remove_button); container.Add(field); field.style.flexGrow = new StyleFloat(1.0f); view.SetEditorField(container); this.items.Add(view); Add(view); m_OnPropertyChange(); return(view); }