UnityImageProcessing_Package/Scripts/Editor/Windows/ImageProcessingGraphNodeVisual.cs
2025-04-26 19:40:12 +01:00

246 lines
9.4 KiB
C#

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<Port> InputPorts { get; }
public List<Port> 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<NodeInfoAttribute>();
title = info.Title;
string[] depths = info.MenuItem.Split('/');
foreach (var depth in depths)
{
this.AddToClassList(depth.ToLower().Replace(' ', '-'));
}
this.InputPorts = new List<Port>();
this.OutputPorts = new List<Port>();
List<Input> inputs = new List<Input>();
List<FieldInfo> inputFieldInfo = new List<FieldInfo>();
List<FieldInfo> outputFieldInfo = new List<FieldInfo>();
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<Input>();
inputs.Add(input);
inputFieldInfo.Add(field);
}
if (field.GetCustomAttribute(typeof(Output)) != null)
{
Output output = field.GetCustomAttribute<Output>();
outputFieldInfo.Add(field);
}
}
CreateInputPorts(inputFieldInfo);
CreateOutputPorts(outputFieldInfo);
this.name = typeInfo.Name;
}
private void CreateInputPorts(List<FieldInfo> 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<Input>().Label;
if (label != "")
port.portName = label;
InputPorts.Add(port);
inputContainer.Add(port);
ExposeVariableToPort(port, field);
}
}
private void CreateOutputPorts(List<FieldInfo> 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<Output>().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<VisualElement>("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());
}
}