148 lines
6.4 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace NanoBrain.Unity {
public class ClusterView {
private static readonly float size = 20;
protected class ViewState {
public string key = null;
public Vector2 scrollPos = Vector2.zero;
public bool expandArray = false;
public Nucleus currentNucleus = null;
}
static Dictionary<string, ViewState> viewStates = new();
private static ViewState GetViewState(SerializedProperty property) {
string key = property.propertyPath + "_" + property.serializedObject.targetObject.GetEntityId();
if (!viewStates.TryGetValue(key, out ViewState state))
state = new() { key = key };
return state;
}
private static void UpdateViewState(ViewState viewState) {
viewStates[viewState.key] = viewState;
}
public static void Render(Rect drawRect, Cluster cluster, SerializedProperty property) {
ViewState state = GetViewState(property);
// background
EditorGUI.DrawRect(drawRect, Color.black);
const float contentWidth = 1000f;
Rect contentRect = new Rect(0f, 0f, contentWidth, drawRect.height);
// Begin horizontal-only scroll view
state.scrollPos = GUI.BeginScrollView(drawRect, state.scrollPos, contentRect, true, false);
// Local content group: draw GUI content using content-local coords (0..contentWidth)
GUI.BeginGroup(new Rect(-state.scrollPos.x, 0f, contentWidth, drawRect.height));
EditorGUI.DrawRect(new Rect(0f, 0f, contentWidth, drawRect.height), new Color(0.08f, 0.08f, 0.08f, 1f));
GUI.EndGroup();
GUI.EndScrollView();
// Clip to drawRect so Handles are not drawn outside the black area
GUI.BeginGroup(drawRect);
// Inner group positions content origin so local coords match content space and respect scroll
GUI.BeginGroup(new Rect(-state.scrollPos.x, 0f, contentWidth, drawRect.height));
Handles.BeginGUI();
DrawNucleus(state, cluster, new Vector2(100, 100), Color.black);
Handles.EndGUI();
GUI.EndGroup(); // end inner group
GUI.EndGroup(); // end clipping group
UpdateViewState(state);
}
protected static void DrawNucleus(ViewState state, Nucleus nucleus, Vector2 position, Color color) {
if (nucleus == null)
return;
if (nucleus == state.currentNucleus) {
// The selected nucleus highlight ring
Handles.color = Color.white;
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
}
if (nucleus is MemoryCell) {
Handles.color = Color.white;
Handles.DrawWireDisc(position + Vector2.right * 10, Vector3.forward, size);
}
Handles.color = color;
Handles.DrawSolidDisc(position, Vector3.forward, size);
Handles.color = Color.white;
// Position the label in front of the disc
//Vector3 labelPosition = position; // + (Vector2.forward * 0.1f);
GUIStyle style = new(EditorStyles.label) {
alignment = TextAnchor.MiddleCenter,
normal = { textColor = Color.white },
fontStyle = FontStyle.Bold,
};
// if (nucleus.parent is Cluster parentCluster && currentNucleus != null && parentCluster != currentNucleus.parent)
// DrawCluster(parentCluster, position, color, size);
// else if (nucleus is Cluster cluster)
// DrawCluster(cluster, position, color, size);
if (state.expandArray == false) {// || nucleus != currentNucleus) {
// put name below nucleus
Vector3 labelPos = position - Vector2.down * (size + 5); // below neuron
style.alignment = TextAnchor.UpperCenter;
if (nucleus.parent != null && state.currentNucleus != null && nucleus.parent != state.currentNucleus.parent && nucleus.parent is Cluster parentCluster1) {
// This neuron is part of another cluster
parentCluster1.name ??= "";
int colonPos = parentCluster1.name.IndexOf(":");
string baseName;
if (colonPos > 0 && colonPos < parentCluster1.name.Length - 2)
baseName = parentCluster1.name[..colonPos] + "\n";
else
baseName = parentCluster1.name + "\n";
Handles.Label(labelPos, baseName + nucleus.name, style);
}
else {
nucleus.name ??= "";
int colonPos = nucleus.name.IndexOf(":");
if (colonPos > 0 && colonPos < nucleus.name.Length - 2) {
// if it is an array, we should not show the :0 of the first element
string baseName = nucleus.name[..colonPos];
Handles.Label(labelPos, baseName, style);
}
else
Handles.Label(labelPos, nucleus.name, style);
}
}
// Tooltip
// 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 Hover
// HandleMouseHover(nucleus, neuronRect);
// // Process click
// if (e.type == EventType.MouseDown && e.button == 0) {
// // Consume the event so the scene doesn't also handle it
// e.Use();
// if (nucleus is Cluster parentCluster2)
// OnNeuronClick(parentCluster2);
// else
// OnNeuronClick(nucleus);
// }
// }
}
}
}