From e17a24974314073106fb50ba4792c87367e2376f Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 22 Apr 2026 11:29:51 +0200 Subject: [PATCH] Cross-cluster editor links --- Editor/Brain_Editor.cs | 4 +-- Editor/ClusterInspector.cs | 10 +++++-- Editor/ClusterViewer.cs | 56 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/Editor/Brain_Editor.cs b/Editor/Brain_Editor.cs index a0de070..8037d8c 100644 --- a/Editor/Brain_Editor.cs +++ b/Editor/Brain_Editor.cs @@ -11,7 +11,7 @@ namespace NanoBrain { protected static VisualElement mainContainer; protected static VisualElement inspectorContainer; - protected Brain component; + public Brain component; private SerializedProperty brainProp; public void OnEnable() { @@ -55,7 +55,7 @@ namespace NanoBrain { return root; } - public static ClusterViewer.GraphView CreateViewer(VisualElement root, ClusterPrefab cluster, Nucleus output, GameObject gameObject) { + public ClusterViewer.GraphView CreateViewer(VisualElement root, ClusterPrefab cluster, Nucleus output, GameObject gameObject) { VisualElement mainContainer = new() { style = { flexDirection = FlexDirection.Row, diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 15fe536..1adbe18 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -9,6 +9,7 @@ namespace NanoBrain { [CustomEditor(typeof(ClusterPrefab))] public class ClusterInspector : ClusterViewer { + public override VisualElement CreateInspectorGUI() { ClusterPrefab prefab = target as ClusterPrefab; if (prefab != null) @@ -23,7 +24,7 @@ namespace NanoBrain { return root; } - public static GraphView CreateInspector(VisualElement root, ClusterPrefab cluster, Nucleus output, GameObject gameObject) { + public GraphView CreateInspector(VisualElement root, ClusterPrefab cluster, Nucleus output, GameObject gameObject) { root.style.paddingLeft = 0; root.style.paddingRight = 0; root.style.paddingTop = 0; @@ -41,6 +42,7 @@ namespace NanoBrain { graphContainer.style.width = 300; graphContainer.style.overflow = Overflow.Hidden; + VisualElement inspectorContainer = new() { name = "inspector", style = { @@ -55,7 +57,7 @@ namespace NanoBrain { mainContainer.Add(inspectorContainer); root.Add(mainContainer); - graphContainer.SetGraph(gameObject, output, inspectorContainer); + graphContainer.SetGraph(gameObject, output, inspectorContainer, this); return graphContainer; } @@ -81,8 +83,10 @@ namespace NanoBrain { this.currentNucleus = newOutput; } - public void SetGraph(GameObject gameObject, Nucleus nucleus, VisualElement inspectorContainer) { + public void SetGraph(GameObject gameObject, Nucleus nucleus, VisualElement inspectorContainer, ClusterInspector editor) { this.gameObject = gameObject; + this.currentEditor = editor; + //this.cluster = brain; if (Application.isPlaying == false) this.serializedBrain = new SerializedObject(this.prefab); diff --git a/Editor/ClusterViewer.cs b/Editor/ClusterViewer.cs index b42a41b..2784689 100644 --- a/Editor/ClusterViewer.cs +++ b/Editor/ClusterViewer.cs @@ -9,6 +9,9 @@ namespace NanoBrain { public class ClusterViewer : Editor { + //public static ClusterViewer previousEditor; + public static ClusterPrefab previousPrefab; + public class GraphView : VisualElement { protected readonly ClusterPrefab prefab; protected SerializedObject serializedBrain; @@ -26,6 +29,9 @@ namespace NanoBrain { protected IMGUIContainer graphContainer; protected readonly PopupField outputsPopup; + public ClusterInspector currentEditor; + //public ClusterViewer previousEditor; + public enum Mode { Focus, Full @@ -101,7 +107,6 @@ namespace NanoBrain { this.currentNucleus = this.selectedOutput; } - bool subscribed = false; void Subscribe() { if (subscribed) return; @@ -118,6 +123,7 @@ namespace NanoBrain { public void SetGraph(GameObject gameObject, Nucleus nucleus) { this.gameObject = gameObject; + if (Application.isPlaying == false) this.serializedBrain = new SerializedObject(this.prefab); this.currentNucleus = nucleus; @@ -387,7 +393,11 @@ namespace NanoBrain { else return; - int nodeCount = receivers.Count(); //neuron != null ? neuron.receivers.Count() : 1; + int nodeCount = receivers.Count(); + if (nucleus == this.selectedOutput && ClusterViewer.previousPrefab != null) { + // Add link to previous editor + nodeCount++; + } // Determine the maximum value in this layer // This is used to 'scale' the output value colors of the nuclei @@ -423,6 +433,11 @@ namespace NanoBrain { DrawNucleus(receiverNucleus, pos, maxValue, size); row++; } + if (nucleus == this.selectedOutput && ClusterViewer.previousPrefab != null) { + Vector3 pos = new(50, margin + row * spacing, 0); + DrawEdge(parentPos, pos); + DrawClusterPrefab(ClusterViewer.previousPrefab, pos, size); + } } private void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) { @@ -650,6 +665,40 @@ namespace NanoBrain { Handles.DrawWireDisc(position, Vector3.forward, size + 5); } + protected void DrawClusterPrefab(ClusterPrefab prefab, Vector2 position, float size) { + Handles.color = Color.black; + Handles.DrawSolidDisc(position, Vector3.forward, size); + // Draw a circle around the disc to indicate this is a Cluster + Handles.color = Color.white; + Handles.DrawWireDisc(position, Vector3.forward, size + 5); + + // put name below nucleus + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.MiddleCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + Vector2 labelPos = position - Vector2.down * (size + 5); // below neuron + style.alignment = TextAnchor.UpperCenter; + Handles.Label(labelPos, prefab.name, style); + + Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process click + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + Selection.activeObject = prefab; + EditorGUIUtility.PingObject(prefab); + ClusterViewer.previousPrefab = null; + CreateEditor(prefab); + } + } + } + protected void DrawEdge(Vector2 from, Vector2 to) { Handles.color = Color.white; Handles.DrawLine(from, to); @@ -705,7 +754,8 @@ namespace NanoBrain { // May be used with storedPrefab... Selection.activeObject = subCluster.prefab; EditorGUIUtility.PingObject(subCluster.prefab); - _ = CreateEditor(subCluster.prefab); + ClusterViewer.previousPrefab = this.prefab; + ClusterInspector newEditor = CreateEditor(subCluster.prefab) as ClusterInspector; } #endregion Graph