/// <summary> /// Make sure our list of PortViews and editables sync up with our NodePorts /// </summary> protected void UpdatePorts() { foreach (var port in target.ports) { if (port.isInput) { AddInputPort(port); } else { AddOutputPort(port); } } var reflectionData = NodeReflection.GetNodeType(target.GetType()); if (reflectionData != null) { foreach (var editable in reflectionData.editables) { AddEditableField(m_SerializedNode.FindPropertyRelative(editable.fieldName)); } } // Toggle visibility of the extension container RefreshExpandedState(); // Update state classes EnableInClassList("hasInputs", inputs.Count > 0); EnableInClassList("hasOutputs", outputs.Count > 0); }
internal void Initialize(Node node, CanvasView canvas, EdgeConnectorListener connectorListener) { viewDataKey = node.ID; Target = node; Canvas = canvas; ReflectionData = NodeReflection.GetNodeType(node.GetType()); ConnectorListener = connectorListener; styleSheets.Add(Resources.Load <StyleSheet>("BlueGraphEditor/NodeView")); AddToClassList("nodeView"); // Add a class name matching the node's name (e.g. `.node-My-Branch`) var ussSafeName = Regex.Replace(Target.Name, @"[^a-zA-Z0-9]+", "-").Trim('-'); AddToClassList($"node-{ussSafeName}"); var errorContainer = new VisualElement { name = "error" }; errorContainer.Add(new VisualElement { name = "error-icon" }); errorMessage = new Label { name = "error-label" }; errorContainer.Add(errorMessage); Insert(0, errorContainer); SetPosition(new Rect(node.Position, Vector2.one)); title = node.Name; if (!ReflectionData.Deletable) { capabilities &= ~Capabilities.Deletable; } if (!ReflectionData.Moveable) { capabilities &= ~Capabilities.Movable; } // Custom OnDestroy() handler via https://forum.unity.com/threads/request-for-visualelement-ondestroy-or-onremoved-event.718814/ RegisterCallback <DetachFromPanelEvent>((e) => Destroy()); RegisterCallback <TooltipEvent>(OnTooltip); node.OnErrorEvent += RefreshErrorState; node.OnValidateEvent += OnValidate; ReloadPorts(); ReloadEditables(); RefreshErrorState(); OnInitialize(); }
protected void ReloadEditables() { var reflectionData = NodeReflection.GetNodeType(Target.GetType()); if (reflectionData != null) { foreach (var editable in reflectionData.Editables) { AddEditableField(editable); } } RefreshExpandedState(); }
protected void OnTooltip(TooltipEvent evt) { // TODO: Better implementation that can be styled if (evt.target == titleContainer.Q("title-label")) { var typeData = NodeReflection.GetNodeType(Target.GetType()); evt.tooltip = typeData?.Help; // Float the tooltip above the node title bar var bound = titleContainer.worldBound; bound.x = 0; bound.y = 0; bound.height *= -1; evt.rect = titleContainer.LocalToWorld(bound); } }
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); }
/// <summary> /// Deserialize a string back into a CopyPasteGraph. /// /// If <c>includeTags</c> are empty, no filtering will be done. Otherwise, /// only nodes with an intersection to one or more tags will be kept. /// </summary> public static CopyPasteGraph Deserialize(string data, IEnumerable <string> includeTags) { var graph = CreateInstance <CopyPasteGraph>(); JsonUtility.FromJsonOverwrite(data, graph); // Remove nodes that aren't on the allow list for tags var allowedAllNodes = true; if (includeTags.Count() > 0) { graph.Nodes = graph.Nodes.FindAll((node) => { var reflectedNode = NodeReflection.GetNodeType(node.GetType()); var allowed = includeTags.Intersect(reflectedNode.Tags).Count() > 0; allowedAllNodes = allowedAllNodes && allowed; return(allowed); }); } // If we're excluding any from the paste content, notify the user. if (!allowedAllNodes) { Debug.LogWarning("Could not paste one or more nodes - not allowed by the target graph"); } // Generate new unique IDs for each node in the list // in case we're copy+pasting back onto the same graph var idMap = new Dictionary <string, string>(); foreach (var node in graph.Nodes) { var newId = Guid.NewGuid().ToString(); idMap[node.ID] = newId; node.ID = newId; } // Remap connections to new node IDs and drop any connections // that were to nodes outside of the subset of pasted nodes foreach (var node in graph.Nodes) { foreach (var port in node.Ports.Values) { var edges = new List <Connection>(port.Connections); port.Connections.Clear(); // Only re-add connections that are in the new pasted subset foreach (var edge in edges) { if (idMap.ContainsKey(edge.NodeID)) { port.Connections.Add(new Connection { NodeID = idMap[edge.NodeID], PortName = edge.PortName }); } } } } return(graph); }