NanoBrain-unitypackage/Editor/ClusterPrefab_Drawer.cs

129 lines
5.1 KiB
C#

using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor;
using System;
using System.Reflection;
namespace NanoBrain.Unity {
[CustomPropertyDrawer(typeof(ClusterPrefab))]
class ClusterPrefab_Drawer : PropertyDrawer {
public static void Insepctor(SerializedObject serializedObject, string propertyName) {
EditorGUILayout.PropertyField(serializedObject.FindProperty(propertyName));
}
const float padding = 4f;
const float elementHeight = 64f; // height reserved for the VisualElement
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
float height = EditorGUIUtility.singleLineHeight + padding;
string key = property.propertyPath + "_" + property.serializedObject.targetObject.GetEntityId();
s_foldouts.TryGetValue(key, out bool isOpen);
if (property.objectReferenceValue != null && isOpen) {
height += padding + elementHeight;
height = 500;
}
else
height = 36;
return height;
}
static readonly Dictionary<string, bool> s_foldouts = new();
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
label = EditorGUI.BeginProperty(position, label, property);
// Begin indent block
int indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
// Draw the object field on the top line
Rect fieldRect = new(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
EditorGUI.PropertyField(fieldRect, property, label);
if (property.objectReferenceValue is ClusterPrefab prefab) {
// key per field instance
string key = property.propertyPath + "_" + property.serializedObject.targetObject.GetEntityId();
if (!s_foldouts.TryGetValue(key, out bool isOpen))
isOpen = true;
// foldout header rect
Rect headerRect = new(fieldRect.x, fieldRect.yMax + 4f, fieldRect.width, EditorGUIUtility.singleLineHeight);
isOpen = EditorGUI.Foldout(headerRect, isOpen, "Graph", true);
s_foldouts[key] = isOpen;
if (isOpen) {
// content rect below header
Rect drawRect = new(fieldRect.x, headerRect.yMax + 2f, fieldRect.width, 450f);
ClusterView.Render(drawRect, prefab.cluster, property);
//Debug.Log(prefab.cluster.defaultOutput.outputMagnitude);
}
}
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
}
/*
[InitializeOnLoad]
static class ClusterPrefabInspectorRepaints {
static ClusterPrefabInspectorRepaints() {
EditorApplication.update += OnEditorUpdate;
}
static double lastRepaint = 0;
const double repaintInterval = 1.0 / 15.0; // up to 15 FPS in inspector
static void OnEditorUpdate() {
if (!Application.isPlaying) return;
// throttle repaint frequency
if (EditorApplication.timeSinceStartup - lastRepaint < repaintInterval) return;
lastRepaint = EditorApplication.timeSinceStartup;
// Find all open inspectors (Editors) that target objects containing ClusterPrefab fields
var editors = Resources.FindObjectsOfTypeAll<Editor>();
foreach (var ed in editors) {
var targets = ed.targets;
if (targets == null)
continue;
bool shouldRepaint = targets.Any(t => ObjectHasClusterPrefabField(t));
if (shouldRepaint) {
try {
ed.Repaint();
}
catch {
// ignore
}
}
}
}
static bool ObjectHasClusterPrefabField(UnityEngine.Object obj) {
if (obj == null)
return false;
Type type = obj.GetType();
// search fields (instance, non-public/public)
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo f in fields) {
if (f.FieldType == typeof(ClusterPrefab))
return true;
// also handle arrays/lists of ClusterPrefab or serializable wrappers:
if (f.FieldType.IsArray && f.FieldType.GetElementType() == typeof(ClusterPrefab))
return true;
if (f.FieldType.IsGenericType) {
Type[] gen = f.FieldType.GetGenericArguments();
if (gen.Length == 1 && gen[0] == typeof(ClusterPrefab))
return true;
}
}
return false;
}
}
*/
}