Cross-cluster editor links

This commit is contained in:
Pascal Serrarens 2026-04-22 11:29:51 +02:00
parent 0ab2d2102d
commit e17a249743
3 changed files with 62 additions and 8 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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<string> 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