using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using ImageProcessingGraph.Editor.Nodes.NodeAttributes; using UnityEditor.Experimental.GraphView; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; using Input = ImageProcessingGraph.Editor.Nodes.NodeAttributes.Input; namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Windows { public class ImageProcessingGraphNodeVisual : Node { private BaseImageNode graphNode; public BaseImageNode GraphNode => graphNode; public List InputPorts { get; } public List OutputPorts { get; } private ImageProcessingGraphViewWindow window; public ImageProcessingGraphNodeVisual(BaseImageNode node, ImageProcessingGraphViewWindow window) { this.AddToClassList("image-node-visual"); this.window = window; graphNode = node; Type typeInfo = node.GetType(); NodeInfoAttribute info = typeInfo.GetCustomAttribute(); title = info.Title; string[] depths = info.MenuItem.Split('/'); foreach (var depth in depths) { this.AddToClassList(depth.ToLower().Replace(' ', '-')); } this.InputPorts = new List(); this.OutputPorts = new List(); List inputs = new List(); List inputFieldInfo = new List(); List outputFieldInfo = new List(); FieldInfo[] fields = typeInfo.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); foreach (var field in fields) { if (field.GetCustomAttribute(typeof(Input)) != null) { Input input = field.GetCustomAttribute(); inputs.Add(input); inputFieldInfo.Add(field); } if (field.GetCustomAttribute(typeof(Output)) != null) { Output output = field.GetCustomAttribute(); outputFieldInfo.Add(field); } } CreateInputPorts(inputFieldInfo); CreateOutputPorts(outputFieldInfo); this.name = typeInfo.Name; } private void CreateInputPorts(List fields) { for (var index = 0; index < fields.Count; index++) { var field = fields[index]; /* Port port = InstantiatePort(Orientation.Horizontal, Direction.Input, Port.Capacity.Multi, field.FieldType); */ var port = IPTPort.Create(window.edgeConnectorListener, true, field.FieldType); string label = field.GetCustomAttribute().Label; if (label != "") port.portName = label; InputPorts.Add(port); inputContainer.Add(port); ExposeVariableToPort(port, field); } } private void CreateOutputPorts(List fields) { for (var index = 0; index < fields.Count; index++) { var field = fields[index]; var port = IPTPort.Create(window.edgeConnectorListener, false, field.FieldType); string label = field.GetCustomAttribute().Label; if (label != "") port.portName = label; OutputPorts.Add(port); outputContainer.Add(port); } } // Exposes a variable on the port for editing when it's not connected private void ExposeVariableToPort(Port port, FieldInfo field) { // Only expose when the port is not connected if (port.connections.Count() == 0) { var propertyFieldContainer = new VisualElement(); propertyFieldContainer.name = "property-field-container"; var propertyField = CreatePropertyFieldForType(field.FieldType, field.GetValue(graphNode)); if (propertyField != null) { // Register a callback for when the value changes if (propertyField is IntegerField intField) { intField.RegisterValueChangedCallback(evt => { field.SetValue(graphNode, evt.newValue); // Update the field with the new value }); } else if (propertyField is FloatField floatField) { floatField.RegisterValueChangedCallback(evt => { field.SetValue(graphNode, evt.newValue); // Update the field with the new value }); } else if (propertyField is Toggle boolField) { boolField.RegisterValueChangedCallback(evt => { field.SetValue(graphNode, evt.newValue); // Update the field with the new value }); } else if (propertyField is TextField stringField) { stringField.RegisterValueChangedCallback(evt => { field.SetValue(graphNode, evt.newValue); // Update the field with the new value }); } else if (propertyField is ColorField colorField) { colorField.RegisterValueChangedCallback(evt => { field.SetValue(graphNode, evt.newValue); // Update the field with the new value }); } else if (propertyField is Vector3Field vector3Field) { vector3Field.RegisterValueChangedCallback(evt => { field.SetValue(graphNode, evt.newValue); // Update the field with the new value }); } else if (propertyField is Vector2Field vector2Field) { vector2Field.RegisterValueChangedCallback(evt => { field.SetValue(graphNode, evt.newValue); // Update the field with the new value }); } else if (propertyField is ObjectField objectField) { objectField.RegisterValueChangedCallback(evt => { field.SetValue(graphNode, evt.newValue); // Update the field with the new value }); } propertyFieldContainer.Add(propertyField); port.Add(propertyFieldContainer); } } else { // If the port is connected, remove the exposed UI element var existingPropertyFieldContainer = port.Q("property-field-container"); if (existingPropertyFieldContainer != null) { port.Remove(existingPropertyFieldContainer); } } } // Create appropriate property field based on the type of the variable private VisualElement CreatePropertyFieldForType(Type type, object value) { if (type == typeof(int)) { var intField = new IntegerField { value = (int)value }; return intField; } else if (type == typeof(float)) { var floatField = new FloatField { value = (float)value }; return floatField; } else if (type == typeof(bool)) { var boolField = new Toggle { value = (bool)value }; return boolField; } else if (type == typeof(string)) { var stringField = new TextField { value = (string)value }; return stringField; } else if (type == typeof(Color)) { var colorField = new ColorField() { value = (Color)value }; return colorField; } else if (type == typeof(Vector3)) { var vector3Field = new Vector3Field { value = (Vector3)value }; return vector3Field; } else if (type == typeof(Vector2)) { var vector2Field = new Vector2Field { value = (Vector2)value }; return vector2Field; } else if (type == typeof(Texture2D)) { var objectField = new ObjectField { value = (Texture2D)value, objectType = typeof(Texture2D) }; return objectField; } // Add more types as needed (Vector3, etc.) return null; } public void SavePosition() => graphNode.SetPosition(GetPosition()); } }