diff --git a/Editor/ClusterView.cs b/Editor/ClusterView.cs index e9d147f..5c53682 100644 --- a/Editor/ClusterView.cs +++ b/Editor/ClusterView.cs @@ -103,6 +103,8 @@ namespace NanoBrain.Unity { public Nucleus currentNucleus = null; public Nucleus selectedSynapseNeuron = null; public Nucleus selectedOutput; + public bool isOpen = true; + public bool initialized; #region Focus Graph diff --git a/Editor/Cluster_Drawer.cs b/Editor/Cluster_Drawer.cs index 989d774..79e9037 100644 --- a/Editor/Cluster_Drawer.cs +++ b/Editor/Cluster_Drawer.cs @@ -1,12 +1,9 @@ -using System.Linq; using System.Collections; using System.Collections.Generic; using System.Reflection; using UnityEngine; -using UnityEngine.UIElements; using UnityEditor; using System; -using System.Reflection; namespace NanoBrain.Unity { @@ -15,7 +12,16 @@ namespace NanoBrain.Unity { static Cluster_Drawer() { SceneView.duringSceneGui += OnSceneGUI; + Selection.selectionChanged += OnSelectionChanged; + if (clusterView != null) + clusterView.initialized = false; } + ~Cluster_Drawer() { + SceneView.duringSceneGui -= OnSceneGUI; + } + + //static readonly Dictionary s_foldouts = new(); + static readonly Dictionary clusterViews = new(); public static void Insepctor(SerializedObject serializedObject, string propertyName) { EditorGUILayout.PropertyField(serializedObject.FindProperty(propertyName)); @@ -26,12 +32,24 @@ namespace NanoBrain.Unity { private static ClusterView clusterView; private static UnityEngine.Object selectedTarget; + public ClusterView GetClusterView(SerializedProperty property) { + string key = property.propertyPath + "_" + property.serializedObject.targetObject.GetInstanceID();//GetEntityId(); + if (clusterViews.TryGetValue(key, out ClusterView view)) + return view; + + view = new ClusterView(); + clusterViews[key] = view; + return view; + } + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { float height = EditorGUIUtility.singleLineHeight + padding; - string key = property.propertyPath + "_" + property.serializedObject.targetObject.GetInstanceID();//GetEntityId(); - s_foldouts.TryGetValue(key, out bool isOpen); + // string key = property.propertyPath + "_" + property.serializedObject.targetObject.GetInstanceID();//GetEntityId(); + // //s_foldouts.TryGetValue(key, out bool isOpen); + // clusterViews.TryGetValue(key, out ClusterView view); + ClusterView view = GetClusterView(property); SerializedProperty prefabProp = property.FindPropertyRelative(nameof(Cluster.prefab)); - if (prefabProp.objectReferenceValue != null && isOpen) { + if (prefabProp.objectReferenceValue != null && view.isOpen) { height += padding + elementHeight; height = 500; } @@ -40,9 +58,10 @@ namespace NanoBrain.Unity { return height; } - static readonly Dictionary s_foldouts = new(); public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + ClusterView clusterView = GetClusterView(property); + label = EditorGUI.BeginProperty(position, label, property); // Begin indent block @@ -73,27 +92,40 @@ namespace NanoBrain.Unity { } if (prefabProp.objectReferenceValue is ClusterPrefab prefab) { + // // Graph is not shown when multi-editing if (property.serializedObject.targetObjects.Length == 1) { - // Graph is not shown when multi-editing UnityEngine.Object targetObject = property.serializedObject.targetObject; Cluster_Drawer.selectedTarget = targetObject; - Cluster cluster = SerializedPropertyUtility.GetManagedObjectForProperty(targetObject, property.propertyPath) as Cluster; + + Cluster cluster; + if (clusterView.initialized) { + cluster = SerializedPropertyUtility.GetManagedObjectForProperty(targetObject, property.propertyPath) as Cluster; + } + else { + ClusterPrefab clusterPrefab = prefabProp.objectReferenceValue as ClusterPrefab; + cluster = new(clusterPrefab); + object parent = SerializedPropertyUtility.GetParentObjectAndMember(targetObject, property.propertyPath, out var memberInfo, out int outIndex); + if (parent != null && memberInfo is FieldInfo fieldInfo) { + fieldInfo.SetValue(parent, cluster); + EditorUtility.SetDirty(targetObject); + } + clusterView.initialized = true; + } // key per field instance string key = property.propertyPath + "_" + property.serializedObject.targetObject.GetInstanceID();//GetEntityId(); - if (!s_foldouts.TryGetValue(key, out bool isOpen)) - isOpen = true; + // 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; + clusterView.isOpen = EditorGUI.Foldout(headerRect, clusterView.isOpen, "Graph", true); - if (isOpen) { + if (clusterView.isOpen) { // content rect below header Rect drawRect = new(fieldRect.x, headerRect.yMax + 2f, fieldRect.width, 450f); - Cluster_Drawer.clusterView = ClusterView.GetClusterView(property); + Cluster_Drawer.clusterView = clusterView; ClusterView.Render(drawRect, cluster, property); //Debug.Log(prefab.cluster.defaultOutput.outputMagnitude); } @@ -105,6 +137,9 @@ namespace NanoBrain.Unity { } private static void OnSceneGUI(SceneView sceneView) { + if (selectedTarget == null) + return; + GameObject gameObject = null; if (selectedTarget is Component c) gameObject = c.gameObject; @@ -125,7 +160,12 @@ namespace NanoBrain.Unity { Handles.DrawLine(gameObject.transform.position, gameObject.transform.position + worldVector); } } + } + private static void OnSelectionChanged() { + foreach (ClusterView clusterView in clusterViews.Values) { + clusterView.initialized = false; + } } } diff --git a/Runtime/Scripts/Core/Cluster.cs b/Runtime/Scripts/Core/Cluster.cs index 78f6504..9417ff1 100644 --- a/Runtime/Scripts/Core/Cluster.cs +++ b/Runtime/Scripts/Core/Cluster.cs @@ -176,7 +176,7 @@ namespace NanoBrain { }; for (int instanceIx = 1; instanceIx < clonedCluster.instanceCount; instanceIx++) { // Create another sibling - Debug.Log($"create {clonedCluster.prefab.name} sibling"); + // Debug.Log($"create {clonedCluster.prefab.name} sibling"); Cluster sibling = new(clonedCluster.prefab, this) { name = $"{clonedCluster.baseName}: {instanceIx}", parent = this.parent, @@ -241,7 +241,7 @@ namespace NanoBrain { } clonedNeuron.AddReceiver(receiver, weight); - Debug.Log($"external: {receiver.name} receives from {clonedNeuron.name} {clonedNeuron.GetHashCode()}"); + // Debug.Log($"external: {receiver.name} receives from {clonedNeuron.name} {clonedNeuron.GetHashCode()}"); } }