using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace Unity.VisualScripting { [Editor(typeof(IUnit))] public class UnitEditor : GraphElementEditor { public UnitEditor(Metadata metadata) : base(metadata) { } protected IUnit unit => (IUnit)element; protected new UnitDescription description => (UnitDescription)base.description; protected new UnitAnalysis analysis => (UnitAnalysis)base.analysis; protected override float GetHeight(float width, GUIContent label) { var height = 0f; height += GetHeaderHeight(width); height += GetWrappedInspectorHeight(width); if (exception != null) { height += GetExceptionHeight(width); } height += analysis.warnings.Sum(warning => warning.GetHeight(width)); if (unit.inputs.Any()) { height += GetPortsHeight(width, new GUIContent("Inputs"), unit.inputs.Cast()); } if (unit.outputs.Any()) { height += GetPortsHeight(width, new GUIContent("Outputs"), unit.outputs.Cast()); } return height; } protected override void OnGUI(Rect position, GUIContent label) { y = 0; OnHeaderGUI(position); EditorGUI.BeginChangeCheck(); OnWrappedInspectorGUI(position); if (EditorGUI.EndChangeCheck()) { unit.Define(); } if (exception != null) { y--; OnExceptionGUI(position.VerticalSection(ref y, GetExceptionHeight(position.width) + 1)); } foreach (var warning in analysis.warnings) { y--; warning.OnGUI(position.VerticalSection(ref y, warning.GetHeight(position.width) + 1)); } if (unit.inputs.Any()) { y--; OnPortsGUI(position, new GUIContent("Inputs"), unit.inputs.Cast()); } if (unit.outputs.Any()) { y--; OnPortsGUI(position, new GUIContent("Outputs"), unit.outputs.Cast()); } } private float GetPortsInnerWidth(float totalWidth) { return totalWidth - Styles.portsBackground.padding.left - Styles.portsBackground.padding.right; } private float GetPortsHeight(float totalWidth, GUIContent label, IEnumerable ports) { var innerWidth = GetPortsInnerWidth(totalWidth); var height = 0f; height += Styles.portsBackground.padding.top; height += Styles.portsLabel.CalcHeight(label, innerWidth); foreach (var port in ports) { height += Styles.spaceBetweenPorts; height += GetPortHeight(innerWidth, port); } height += Styles.portsBackground.padding.bottom; return height; } private void OnPortsGUI(Rect position, GUIContent label, IEnumerable ports) { var backgroundPosition = new Rect ( position.x, y, position.width, GetPortsHeight(position.width, label, ports) ); if (e.type == EventType.Repaint) { Styles.portsBackground.Draw(backgroundPosition, false, false, false, false); } var innerWidth = GetPortsInnerWidth(position.width); y += Styles.portsBackground.padding.top; position.x += Styles.portsBackground.padding.left; var labelPosition = new Rect ( position.x, y, innerWidth, Styles.portsLabel.CalcHeight(label, innerWidth) ); GUI.Label(labelPosition, label, Styles.portsLabel); y += labelPosition.height; foreach (var port in ports) { y += Styles.spaceBetweenPorts; var portPosition = new Rect ( position.x, y, innerWidth, GetPortHeight(innerWidth, port) ); OnPortGUI(portPosition, port); y += portPosition.height; } y += Styles.portsBackground.padding.bottom; } private GUIContent GetLabelContent(IUnitPort port) { string type; if (port is IUnitControlPort) { type = "Flow"; } else if (port is IUnitValuePort) { type = ((IUnitValuePort)port).type.DisplayName(); } else if (port is IUnitInvalidPort) { type = "Invalid"; } else { throw new NotSupportedException(); } return new GUIContent(string.Format($"{port.Description().label} : {LudiqGUIUtility.EscapeRichText(type)}")); } private float GetPortHeight(float paddedWidth, IUnitPort port) { var portDescription = port.Description(); var labelWidth = paddedWidth - Styles.portIcon.fixedWidth - Styles.portIcon.margin.right; var height = 0f; height += Styles.portLabel.CalcHeight(GetLabelContent(port), labelWidth); var summary = portDescription.summary; if (!StringUtility.IsNullOrWhiteSpace(summary)) { height += Styles.portDescription.CalcHeight(new GUIContent(summary), labelWidth); } return height; } private void OnPortGUI(Rect portPosition, IUnitPort port) { var portDescription = port.Description(); var labelWidth = portPosition.width - Styles.portIcon.fixedWidth - Styles.portIcon.margin.right; var iconPosition = new Rect ( portPosition.x, portPosition.y, Styles.portIcon.fixedWidth, Styles.portIcon.fixedHeight ); var icon = portDescription.icon?[IconSize.Small]; if (icon != null) { GUI.DrawTexture(iconPosition, icon); } var labelContent = GetLabelContent(port); var labelPosition = new Rect ( iconPosition.xMax + Styles.portIcon.margin.right, portPosition.y, labelWidth, Styles.portLabel.CalcHeight(labelContent, labelWidth) ); GUI.Label(labelPosition, labelContent, Styles.portLabel); var summary = portDescription.summary; if (!StringUtility.IsNullOrWhiteSpace(summary)) { var descriptionContent = new GUIContent(summary); var descriptionPosition = new Rect ( labelPosition.x, labelPosition.yMax, labelWidth, Styles.portDescription.CalcHeight(descriptionContent, labelWidth) ); GUI.Label(descriptionPosition, descriptionContent, Styles.portDescription); } } public new static class Styles { static Styles() { portsBackground = new GUIStyle("IN BigTitle"); portsBackground.padding = new RectOffset(10, 5, 7, 10); portsLabel = new GUIStyle(EditorStyles.label); portsLabel.fontSize = 13; portsLabel.padding = new RectOffset(0, 0, 0, 3); portLabel = new GUIStyle(EditorStyles.label); portLabel.imagePosition = ImagePosition.TextOnly; portLabel.wordWrap = true; portLabel.richText = true; portDescription = new GUIStyle(EditorStyles.label); portDescription.imagePosition = ImagePosition.TextOnly; portDescription.wordWrap = true; portDescription.richText = true; portDescription.fontSize = 10; portDescription.normal.textColor = ColorPalette.unityForegroundDim; portIcon = new GUIStyle(); portIcon.imagePosition = ImagePosition.ImageOnly; portIcon.fixedWidth = portIcon.fixedHeight = IconSize.Small; portIcon.margin.right = 5; inspectorBackground = new GUIStyle(); inspectorBackground.padding = new RectOffset(10, 10, 10, 10); } public static readonly GUIStyle portsBackground; public static readonly GUIStyle portsLabel; public static readonly GUIStyle portLabel; public static readonly GUIStyle portDescription; public static readonly GUIStyle portIcon; public static readonly float spaceBetweenPorts = 5; public static readonly GUIStyle inspectorBackground; } } }