public static void PropertyAndPortPair(SerializedObject so, XNode.NodePort input, XNode.NodePort output) { XNode.Node.ShowBackingValue showBacking = XNode.Node.ShowBackingValue.Unconnected; XNode.Node.InputAttribute inputAttribute; bool dynamicPortList = false; if (NodeEditorUtilities.GetCachedAttrib(input.node.GetType(), input.fieldName, out inputAttribute)) { dynamicPortList = inputAttribute.dynamicPortList; showBacking = inputAttribute.backingValue; } bool usePropertyAttributes = dynamicPortList || showBacking == XNode.Node.ShowBackingValue.Never || (showBacking == XNode.Node.ShowBackingValue.Unconnected && input.IsConnected); if (!usePropertyAttributes) { PropertyField(so.FindProperty(input.fieldName)); PortField(output); } else { PortPair(input, output); } }
/// <summary> Make a field for a serialized property. Manual node port override. </summary> public static void PropertyField(SerializedProperty property, GUIContent label, XNode.NodeLinkPort con) { Rect rect = new Rect(); XNode.Node node = con.Node; XNode.NodeLinkDefinition link = con.Link; XNode.Node.InputAttribute inputAttribute = link.InputAttribute; XNode.Node.OutputAttribute outputAttribute = link.OutputAttribute; List <PropertyAttribute> propertyAttributes = NodeEditorUtilities.GetCachedPropertyAttribs(node.GetType(), property.name); float spacePadding = 0; foreach (var attr in propertyAttributes) { if (attr is SpaceAttribute) { spacePadding += (attr as SpaceAttribute).height; } } if (inputAttribute != null) { EditorGUILayout.LabelField(label ?? new GUIContent(property.displayName)); rect = GUILayoutUtility.GetLastRect(); rect.position = rect.position - new Vector2(16, -spacePadding); } // If property is an output, display a text label and put a port handle on the right side else if (outputAttribute != null) { // Get data from [Output] attribute bool dynamicPortList = outputAttribute.dynamicPortList; XNode.Node.ShowBackingValue showBacking = outputAttribute.backingValue; EditorGUILayout.LabelField(label ?? new GUIContent(property.displayName), NodeEditorResources.OutputPort, GUILayout.MinWidth(30)); rect = GUILayoutUtility.GetLastRect(); rect.position = rect.position + new Vector2(rect.width, spacePadding); } rect.size = new Vector2(16, 16); NodeEditor editor = NodeEditor.GetEditor(node, NodeEditorWindow.current); Color backgroundColor = editor.GetTint(); Color col = NodeEditorWindow.current.graphEditor.GetLinkColor(link); DrawPortHandle(rect, backgroundColor, col); // Register the handle position Vector2 portPos = rect.center; NodeEditor.linkPositions[con] = portPos; }
/// <summary> Make a field for a serialized property. Manual node port override. </summary> public static void PropertyField(SerializedProperty property, GUIContent label, XNode.NodePort port, bool includeChildren = true, params GUILayoutOption[] options) { if (property == null) { throw new NullReferenceException(); } // If property is not a port, display a regular property field if (port == null) { EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); } else { Rect rect = new Rect(); List <PropertyAttribute> propertyAttributes = NodeEditorUtilities.GetCachedPropertyAttribs(port.node.GetType(), property.name); // If property is an input, display a regular property field and put a port handle on the left side if (port.direction == XNode.NodePort.IO.Input) { // Get data from [Input] attribute XNode.Node.ShowBackingValue showBacking = XNode.Node.ShowBackingValue.Unconnected; XNode.Node.InputAttribute inputAttribute; bool dynamicPortList = false; if (NodeEditorUtilities.GetCachedAttrib(port.node.GetType(), property.name, out inputAttribute)) { dynamicPortList = inputAttribute.dynamicPortList; showBacking = inputAttribute.backingValue; } bool usePropertyAttributes = dynamicPortList || showBacking == XNode.Node.ShowBackingValue.Never || (showBacking == XNode.Node.ShowBackingValue.Unconnected && port.IsConnected); float spacePadding = 0; foreach (var attr in propertyAttributes) { if (attr is SpaceAttribute) { if (usePropertyAttributes) { GUILayout.Space((attr as SpaceAttribute).height); } else { spacePadding += (attr as SpaceAttribute).height; } } else if (attr is HeaderAttribute) { if (usePropertyAttributes) { //GUI Values are from https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/ScriptAttributeGUI/Implementations/DecoratorDrawers.cs Rect position = GUILayoutUtility.GetRect(0, (EditorGUIUtility.singleLineHeight * 1.5f) - EditorGUIUtility.standardVerticalSpacing); //Layout adds standardVerticalSpacing after rect so we subtract it. position.yMin += EditorGUIUtility.singleLineHeight * 0.5f; position = EditorGUI.IndentedRect(position); GUI.Label(position, (attr as HeaderAttribute).header, EditorStyles.boldLabel); } else { spacePadding += EditorGUIUtility.singleLineHeight * 1.5f; } } } if (dynamicPortList) { Type type = GetType(property); XNode.Node.ConnectionType connectionType = inputAttribute != null ? inputAttribute.connectionType : XNode.Node.ConnectionType.Multiple; DynamicPortList(property.name, type, property.serializedObject, port.direction, connectionType); return; } switch (showBacking) { case XNode.Node.ShowBackingValue.Unconnected: // Display a label if port is connected if (port.IsConnected) { EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName)); } // Display an editable property field if port is not connected else { EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); } break; case XNode.Node.ShowBackingValue.Never: // Display a label EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName)); break; case XNode.Node.ShowBackingValue.Always: // Display an editable property field EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); break; } rect = GUILayoutUtility.GetLastRect(); rect.position = rect.position - new Vector2(16, -spacePadding); // If property is an output, display a text label and put a port handle on the right side } else if (port.direction == XNode.NodePort.IO.Output) { // Get data from [Output] attribute XNode.Node.ShowBackingValue showBacking = XNode.Node.ShowBackingValue.Unconnected; XNode.Node.OutputAttribute outputAttribute; bool dynamicPortList = false; if (NodeEditorUtilities.GetCachedAttrib(port.node.GetType(), property.name, out outputAttribute)) { dynamicPortList = outputAttribute.dynamicPortList; showBacking = outputAttribute.backingValue; } bool usePropertyAttributes = dynamicPortList || showBacking == XNode.Node.ShowBackingValue.Never || (showBacking == XNode.Node.ShowBackingValue.Unconnected && port.IsConnected); float spacePadding = 0; foreach (var attr in propertyAttributes) { if (attr is SpaceAttribute) { if (usePropertyAttributes) { GUILayout.Space((attr as SpaceAttribute).height); } else { spacePadding += (attr as SpaceAttribute).height; } } else if (attr is HeaderAttribute) { if (usePropertyAttributes) { //GUI Values are from https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/ScriptAttributeGUI/Implementations/DecoratorDrawers.cs Rect position = GUILayoutUtility.GetRect(0, (EditorGUIUtility.singleLineHeight * 1.5f) - EditorGUIUtility.standardVerticalSpacing); //Layout adds standardVerticalSpacing after rect so we subtract it. position.yMin += EditorGUIUtility.singleLineHeight * 0.5f; position = EditorGUI.IndentedRect(position); GUI.Label(position, (attr as HeaderAttribute).header, EditorStyles.boldLabel); } else { spacePadding += EditorGUIUtility.singleLineHeight * 1.5f; } } } if (dynamicPortList) { Type type = GetType(property); XNode.Node.ConnectionType connectionType = outputAttribute != null ? outputAttribute.connectionType : XNode.Node.ConnectionType.Multiple; DynamicPortList(property.name, type, property.serializedObject, port.direction, connectionType); return; } switch (showBacking) { case XNode.Node.ShowBackingValue.Unconnected: // Display a label if port is connected if (port.IsConnected) { EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName), NodeEditorResources.OutputPort, GUILayout.MinWidth(30)); } // Display an editable property field if port is not connected else { EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); } break; case XNode.Node.ShowBackingValue.Never: // Display a label EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName), NodeEditorResources.OutputPort, GUILayout.MinWidth(30)); break; case XNode.Node.ShowBackingValue.Always: // Display an editable property field EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); break; } rect = GUILayoutUtility.GetLastRect(); rect.position = rect.position + new Vector2(rect.width, spacePadding); } rect.size = new Vector2(16, 16); NodeEditor editor = NodeEditor.GetEditor(port.node, NodeEditorWindow.current); Color backgroundColor = editor.GetTint(); Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port); DrawPortHandle(rect, backgroundColor, col); // Register the handle position Vector2 portPos = rect.center; NodeEditor.portPositions[port] = portPos; } }
/// <summary> Make a field for a serialized property. Manual node port override. </summary> public static void PropertyField(SerializedProperty property, GUIContent label, XNode.NodePort port, bool includeChildren = true, params GUILayoutOption[] options) { if (property == null) { throw new NullReferenceException(); } // If property is not a port, display a regular property field if (port == null) { EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); } else { Rect rect = new Rect(); // If property is an input, display a regular property field and put a port handle on the left side if (port.direction == XNode.NodePort.IO.Input) { // Get data from [Input] attribute XNode.Node.ShowBackingValue showBacking = XNode.Node.ShowBackingValue.Unconnected; XNode.Node.InputAttribute inputAttribute; if (NodeEditorUtilities.GetAttrib(port.node.GetType(), property.name, out inputAttribute)) { showBacking = inputAttribute.backingValue; } switch (showBacking) { case XNode.Node.ShowBackingValue.Unconnected: // Display a label if port is connected if (port.IsConnected) { EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName)); } // Display an editable property field if port is not connected else { EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); } break; case XNode.Node.ShowBackingValue.Never: // Display a label EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName)); break; case XNode.Node.ShowBackingValue.Always: // Display an editable property field EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); break; } rect = GUILayoutUtility.GetLastRect(); rect.position = rect.position - new Vector2(16, 0); // If property is an output, display a text label and put a port handle on the right side } else if (port.direction == XNode.NodePort.IO.Output) { // Get data from [Output] attribute XNode.Node.ShowBackingValue showBacking = XNode.Node.ShowBackingValue.Unconnected; XNode.Node.OutputAttribute outputAttribute; if (NodeEditorUtilities.GetAttrib(port.node.GetType(), property.name, out outputAttribute)) { showBacking = outputAttribute.backingValue; } switch (showBacking) { case XNode.Node.ShowBackingValue.Unconnected: // Display a label if port is connected if (port.IsConnected) { EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName), NodeEditorResources.OutputPort, GUILayout.MinWidth(30)); } // Display an editable property field if port is not connected else { EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); } break; case XNode.Node.ShowBackingValue.Never: // Display a label EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName), NodeEditorResources.OutputPort, GUILayout.MinWidth(30)); break; case XNode.Node.ShowBackingValue.Always: // Display an editable property field EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); break; } rect = GUILayoutUtility.GetLastRect(); rect.position = rect.position + new Vector2(rect.width, 0); } rect.size = new Vector2(16, 16); Color backgroundColor = new Color32(90, 97, 105, 255); if (NodeEditorWindow.nodeTint.ContainsKey(port.node.GetType())) { backgroundColor *= NodeEditorWindow.nodeTint[port.node.GetType()]; } Color col = NodeEditorWindow.current.graphEditor.GetTypeColor(port.ValueType); DrawPortHandle(rect, backgroundColor, col); // Register the handle position Vector2 portPos = rect.center; if (NodeEditor.portPositions.ContainsKey(port)) { NodeEditor.portPositions[port] = portPos; } else { NodeEditor.portPositions.Add(port, portPos); } } }
/// <summary> Make a field for a serialized property. Manual node port override. </summary> public static void PropertyField(SerializedProperty property, GUIContent label, XNode.NodePort port, bool includeChildren = true, params GUILayoutOption[] options) { if (property == null) { throw new NullReferenceException(); } // If property is not a port, display a regular property field if (port == null) { EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); } else { Rect rect = new Rect(); float spacePadding = 0; SpaceAttribute spaceAttribute; if (NodeEditorUtilities.GetCachedAttrib(port.node.GetType(), property.name, out spaceAttribute)) { spacePadding = spaceAttribute.height; } // If property is an input, display a regular property field and put a port handle on the left side if (port.direction == XNode.NodePort.IO.Input) { // Get data from [Input] attribute XNode.Node.ShowBackingValue showBacking = XNode.Node.ShowBackingValue.Unconnected; XNode.Node.InputAttribute inputAttribute; bool dynamicPortList = false; if (NodeEditorUtilities.GetCachedAttrib(port.node.GetType(), property.name, out inputAttribute)) { dynamicPortList = inputAttribute.dynamicPortList; showBacking = inputAttribute.backingValue; } //Call GUILayout.Space if Space attribute is set and we are NOT drawing a PropertyField bool useLayoutSpace = dynamicPortList || showBacking == XNode.Node.ShowBackingValue.Never || (showBacking == XNode.Node.ShowBackingValue.Unconnected && port.IsConnected); if (spacePadding > 0 && useLayoutSpace) { GUILayout.Space(spacePadding); spacePadding = 0; } if (dynamicPortList) { Type type = GetType(property); XNode.Node.ConnectionType connectionType = inputAttribute != null ? inputAttribute.connectionType : XNode.Node.ConnectionType.Multiple; DynamicPortList(property.name, type, property.serializedObject, port.direction, connectionType); return; } switch (showBacking) { case XNode.Node.ShowBackingValue.Unconnected: // Display a label if port is connected if (port.IsConnected) { EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName)); } // Display an editable property field if port is not connected else { EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); } break; case XNode.Node.ShowBackingValue.Never: // Display a label EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName)); break; case XNode.Node.ShowBackingValue.Always: // Display an editable property field EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); break; } rect = GUILayoutUtility.GetLastRect(); rect.position = rect.position - new Vector2(16, -spacePadding); // If property is an output, display a text label and put a port handle on the right side } else if (port.direction == XNode.NodePort.IO.Output) { // Get data from [Output] attribute XNode.Node.ShowBackingValue showBacking = XNode.Node.ShowBackingValue.Unconnected; XNode.Node.OutputAttribute outputAttribute; bool dynamicPortList = false; if (NodeEditorUtilities.GetCachedAttrib(port.node.GetType(), property.name, out outputAttribute)) { dynamicPortList = outputAttribute.dynamicPortList; showBacking = outputAttribute.backingValue; } //Call GUILayout.Space if Space attribute is set and we are NOT drawing a PropertyField bool useLayoutSpace = dynamicPortList || showBacking == XNode.Node.ShowBackingValue.Never || (showBacking == XNode.Node.ShowBackingValue.Unconnected && port.IsConnected); if (spacePadding > 0 && useLayoutSpace) { GUILayout.Space(spacePadding); spacePadding = 0; } if (dynamicPortList) { Type type = GetType(property); XNode.Node.ConnectionType connectionType = outputAttribute != null ? outputAttribute.connectionType : XNode.Node.ConnectionType.Multiple; DynamicPortList(property.name, type, property.serializedObject, port.direction, connectionType); return; } switch (showBacking) { case XNode.Node.ShowBackingValue.Unconnected: // Display a label if port is connected if (port.IsConnected) { EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName), NodeEditorResources.OutputPort, GUILayout.MinWidth(30)); } // Display an editable property field if port is not connected else { EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); } break; case XNode.Node.ShowBackingValue.Never: // Display a label EditorGUILayout.LabelField(label != null ? label : new GUIContent(property.displayName), NodeEditorResources.OutputPort, GUILayout.MinWidth(30)); break; case XNode.Node.ShowBackingValue.Always: // Display an editable property field EditorGUILayout.PropertyField(property, label, includeChildren, GUILayout.MinWidth(30)); break; } rect = GUILayoutUtility.GetLastRect(); rect.position = rect.position + new Vector2(rect.width, spacePadding); } rect.size = new Vector2(16, 16); NodeEditor editor = NodeEditor.GetEditor(port.node, NodeEditorWindow.current); Color backgroundColor = editor.GetTint(); Color col = NodeEditorWindow.current.graphEditor.GetPortColor(port); DrawPortHandle(rect, backgroundColor, col); // Register the handle position Vector2 portPos = rect.center; NodeEditor.portPositions[port] = portPos; } }