/// <summary> Draws standard field editors for all public fields </summary> public virtual void OnBodyGUI() { // Unity specifically requires this to save/update any serial object. // serializedObject.Update(); must go at the start of an inspector gui, and // serializedObject.ApplyModifiedProperties(); goes at the end. serializedObject.Update(); string[] excludes = { "m_Script", "graph", "position", "ports" }; EditorUtility.SetDirty(target); NodeEditorGUILayout.AddPortField(target.GetInputPort("PreviousNode")); NodeEditorGUILayout.AddPortField(target.GetOutputPort("NextNode")); // Iterate through serialized properties and draw them like the Inspector (But with ports) SerializedProperty iterator = serializedObject.GetIterator(); bool enterChildren = true; EditorGUIUtility.labelWidth = 130; while (iterator.NextVisible(enterChildren)) { enterChildren = false; if (excludes.Contains(iterator.name)) { continue; } NodeEditorGUILayout.PropertyField(iterator, true); } // Iterate through dynamic ports and draw them in the order in which they are serialized foreach (XNode.NodePort dynamicPort in target.DynamicPorts) { if (NodeEditorGUILayout.IsDynamicPortListPort(dynamicPort)) { continue; } NodeEditorGUILayout.PortField(dynamicPort); } serializedObject.ApplyModifiedProperties(); }
/// <summary> Draw an editable list of instance ports. Port names are named as "[fieldName] [index]" </summary> /// <param name="fieldName">Supply a list for editable values</param> /// <param name="type">Value type of added instance ports</param> /// <param name="serializedObject">The serializedObject of the node</param> /// <param name="connectionType">Connection type of added instance ports</param> public static void InstancePortList(string fieldName, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple) { XNode.Node node = serializedObject.targetObject as XNode.Node; SerializedProperty arrayData = serializedObject.FindProperty(fieldName); bool hasArrayData = arrayData != null && arrayData.isArray; int arraySize = hasArrayData ? arrayData.arraySize : 0; Predicate <string> isMatchingInstancePort = x => { string[] split = x.Split(' '); if (split != null && split.Length == 2) { return(split[0] == fieldName); } else { return(false); } }; List <XNode.NodePort> instancePorts = node.InstancePorts.Where(x => isMatchingInstancePort(x.fieldName)).OrderBy(x => x.fieldName).ToList(); for (int i = 0; i < instancePorts.Count(); i++) { GUILayout.BeginHorizontal(); // 'Remove' button if (GUILayout.Button("-", GUILayout.Width(20))) { // Clear the removed ports connections instancePorts[i].ClearConnections(); // Move following connections one step up to replace the missing connection for (int k = i + 1; k < instancePorts.Count(); k++) { for (int j = 0; j < instancePorts[k].ConnectionCount; j++) { XNode.NodePort other = instancePorts[k].GetConnection(j); instancePorts[k].Disconnect(other); instancePorts[k - 1].Connect(other); } } // Remove the last instance port, to avoid messing up the indexing node.RemoveInstancePort(instancePorts[instancePorts.Count() - 1].fieldName); serializedObject.Update(); EditorUtility.SetDirty(node); if (hasArrayData) { arrayData.DeleteArrayElementAtIndex(i); arraySize--; // Error handling. If the following happens too often, file a bug report at https://github.com/Siccity/xNode/issues if (instancePorts.Count <= arraySize) { while (instancePorts.Count <= arraySize) { arrayData.DeleteArrayElementAtIndex(--arraySize); } Debug.LogWarning("Array size exceeded instance ports size. Excess items removed."); } serializedObject.ApplyModifiedProperties(); serializedObject.Update(); } i--; GUILayout.EndHorizontal(); } else { if (hasArrayData) { if (i < arraySize) { SerializedProperty itemData = arrayData.GetArrayElementAtIndex(i); if (itemData != null) { EditorGUILayout.PropertyField(itemData, new GUIContent(ObjectNames.NicifyVariableName(fieldName) + " " + i), true); } else { EditorGUILayout.LabelField("[Missing array data]"); } } else { EditorGUILayout.LabelField("[Out of bounds]"); } } else { EditorGUILayout.LabelField(instancePorts[i].fieldName); } GUILayout.EndHorizontal(); NodeEditorGUILayout.AddPortField(node.GetPort(instancePorts[i].fieldName)); } // GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); // 'Add' button if (GUILayout.Button("+", GUILayout.Width(20))) { string newName = fieldName + " 0"; int i = 0; while (node.HasPort(newName)) { newName = fieldName + " " + (++i); } if (io == XNode.NodePort.IO.Output) { node.AddInstanceOutput(type, connectionType, newName); } else { node.AddInstanceInput(type, connectionType, newName); } serializedObject.Update(); EditorUtility.SetDirty(node); if (hasArrayData) { arrayData.InsertArrayElementAtIndex(arraySize); } serializedObject.ApplyModifiedProperties(); } GUILayout.EndHorizontal(); }