Adde full graph scrollbar
This commit is contained in:
parent
471ed3661c
commit
02047a4bd9
@ -67,16 +67,16 @@ namespace NanoBrain {
|
|||||||
Button addButton = new(() => OnAddClusterOutput()) {
|
Button addButton = new(() => OnAddClusterOutput()) {
|
||||||
text = "Add"
|
text = "Add"
|
||||||
};
|
};
|
||||||
outputContainer.Add(addButton);
|
topMenuContainer?.Add(addButton);
|
||||||
|
|
||||||
Add(outputContainer);
|
Add(topMenuContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnAddClusterOutput() {
|
void OnAddClusterOutput() {
|
||||||
Nucleus newOutput = new Neuron(this.prefab, "New Output");
|
Nucleus newOutput = new Neuron(this.prefab, "New Output");
|
||||||
this.prefab.RefreshOutputs();
|
this.prefab.RefreshOutputs();
|
||||||
outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
outputsPopup.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
||||||
outputsField.value = newOutput.name;
|
outputsPopup.value = newOutput.name;
|
||||||
|
|
||||||
this.currentNucleus = newOutput;
|
this.currentNucleus = newOutput;
|
||||||
}
|
}
|
||||||
@ -88,7 +88,8 @@ namespace NanoBrain {
|
|||||||
this.serializedBrain = new SerializedObject(this.prefab);
|
this.serializedBrain = new SerializedObject(this.prefab);
|
||||||
this.currentNucleus = nucleus;
|
this.currentNucleus = nucleus;
|
||||||
Rebuild(inspectorContainer);
|
Rebuild(inspectorContainer);
|
||||||
OnOutputChanged(outputsField.choices[0]);
|
if (outputsPopup != null)
|
||||||
|
OnOutputChanged(outputsPopup.choices[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rebuild(VisualElement inspectorContainer) {
|
void Rebuild(VisualElement inspectorContainer) {
|
||||||
@ -173,7 +174,7 @@ namespace NanoBrain {
|
|||||||
if (newName != this.currentNucleus.name) {
|
if (newName != this.currentNucleus.name) {
|
||||||
this.currentNucleus.name = newName;
|
this.currentNucleus.name = newName;
|
||||||
this.prefab.RefreshOutputs();
|
this.prefab.RefreshOutputs();
|
||||||
outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
outputsPopup.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
||||||
anythingChanged = true;
|
anythingChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -492,10 +493,10 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
this.prefab.nuclei.Remove(nucleus);
|
this.prefab.nuclei.Remove(nucleus);
|
||||||
|
|
||||||
if (outputsField.value == nucleus.name) {
|
if (outputsPopup.value == nucleus.name) {
|
||||||
this.prefab.RefreshOutputs();
|
this.prefab.RefreshOutputs();
|
||||||
outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
outputsPopup.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
||||||
outputsField.index = 0;
|
outputsPopup.index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Neuron.Delete(nucleus);
|
Neuron.Delete(nucleus);
|
||||||
|
|||||||
@ -13,14 +13,18 @@ namespace NanoBrain {
|
|||||||
protected readonly ClusterPrefab prefab;
|
protected readonly ClusterPrefab prefab;
|
||||||
protected SerializedObject serializedBrain;
|
protected SerializedObject serializedBrain;
|
||||||
protected Nucleus currentNucleus;
|
protected Nucleus currentNucleus;
|
||||||
|
protected Nucleus selectedOutput;
|
||||||
|
|
||||||
protected GameObject gameObject;
|
protected GameObject gameObject;
|
||||||
private List<NeuroidLayer> layers = new();
|
private List<NeuroidLayer> layers = new();
|
||||||
private readonly Dictionary<Nucleus, Vector2Int> neuroidPositions = new();
|
private readonly Dictionary<Nucleus, Vector2Int> neuroidPositions = new();
|
||||||
private bool expandArray = false;
|
private bool expandArray = false;
|
||||||
|
|
||||||
protected ClusterPrefab prefabAsset;
|
protected ClusterPrefab prefabAsset;
|
||||||
protected VisualElement outputContainer;
|
protected VisualElement topMenuContainer;
|
||||||
protected readonly PopupField<string> outputsField;
|
protected ScrollView scrollView;
|
||||||
|
protected IMGUIContainer graphContainer;
|
||||||
|
protected readonly PopupField<string> outputsPopup;
|
||||||
|
|
||||||
public enum Mode {
|
public enum Mode {
|
||||||
Focus,
|
Focus,
|
||||||
@ -34,37 +38,49 @@ namespace NanoBrain {
|
|||||||
name = "content";
|
name = "content";
|
||||||
style.flexGrow = 1;
|
style.flexGrow = 1;
|
||||||
|
|
||||||
IMGUIContainer graphContainer = new(OnIMGUI);
|
topMenuContainer = new() {
|
||||||
graphContainer.style.position = Position.Absolute;
|
|
||||||
graphContainer.style.left = 0; graphContainer.style.top = 0;
|
|
||||||
graphContainer.style.right = 0; graphContainer.style.bottom = 0;
|
|
||||||
graphContainer.pickingMode = PickingMode.Position;
|
|
||||||
graphContainer.focusable = true;
|
|
||||||
Add(graphContainer);
|
|
||||||
|
|
||||||
outputContainer = new() {
|
|
||||||
style = {
|
style = {
|
||||||
flexDirection = FlexDirection.Row,
|
flexDirection = FlexDirection.Row,
|
||||||
alignItems = Align.Center,
|
alignItems = Align.Center,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
EnumField enumField = new(mode);
|
EnumField modePopup = new(mode);
|
||||||
enumField.style.width = 80;
|
modePopup.style.width = 80;
|
||||||
enumField.RegisterValueChangedCallback(OnModeChange);
|
modePopup.RegisterValueChangedCallback(OnModeChange);
|
||||||
outputContainer.Add(enumField);
|
topMenuContainer.Add(modePopup);
|
||||||
|
|
||||||
|
|
||||||
List<string> names = this.prefab.outputs.Select(output => output.name).ToList();
|
List<string> names = this.prefab.outputs.Select(output => output.name).ToList();
|
||||||
if (names.Count > 0 && names.First() != null) {
|
if (names.Count > 0 && names.First() != null) {
|
||||||
outputsField = new(names, names.First()) {
|
outputsPopup = new(names, names.First()) {
|
||||||
style = { flexGrow = 1 }
|
style = { flexGrow = 1 }
|
||||||
};
|
};
|
||||||
outputsField.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue));
|
outputsPopup.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue));
|
||||||
outputContainer.Add(outputsField);
|
topMenuContainer.Add(outputsPopup);
|
||||||
}
|
}
|
||||||
|
Add(topMenuContainer);
|
||||||
|
|
||||||
|
scrollView = new(ScrollViewMode.Horizontal);
|
||||||
|
scrollView.style.position = Position.Absolute;
|
||||||
|
scrollView.style.left = 0; scrollView.style.top = 0;
|
||||||
|
scrollView.style.right = 0; scrollView.style.bottom = 0;
|
||||||
|
//scrollView.style.flexGrow = 1;
|
||||||
|
scrollView.horizontalScrollerVisibility = ScrollerVisibility.Auto; // Auto shows when needed
|
||||||
|
scrollView.verticalScrollerVisibility = ScrollerVisibility.Hidden;
|
||||||
|
|
||||||
|
graphContainer = new(OnIMGUI);
|
||||||
|
//graphContainer.style.position = Position.Relative; // or omit this line
|
||||||
|
//graphContainer.style.position = Position.Absolute;
|
||||||
|
// graphContainer.style.left = 0; graphContainer.style.top = 0;
|
||||||
|
// graphContainer.style.right = 0; graphContainer.style.bottom = 0;
|
||||||
|
graphContainer.pickingMode = PickingMode.Position;
|
||||||
|
graphContainer.focusable = true;
|
||||||
|
//graphContainer.style.width = 1200;
|
||||||
|
//graphContainer.style.width = new StyleLength(StyleKeyword.Null); // allow content to determine width
|
||||||
|
|
||||||
|
scrollView.contentContainer.Add(graphContainer);
|
||||||
|
Add(scrollView);
|
||||||
|
|
||||||
Add(outputContainer);
|
|
||||||
|
|
||||||
// Subscribe when added to panel (editor UI ready)
|
// Subscribe when added to panel (editor UI ready)
|
||||||
RegisterCallback<AttachToPanelEvent>(evt => Subscribe());
|
RegisterCallback<AttachToPanelEvent>(evt => Subscribe());
|
||||||
@ -75,7 +91,6 @@ namespace NanoBrain {
|
|||||||
mode = (Mode)evt.newValue;
|
mode = (Mode)evt.newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Nucleus selectedOutput;
|
|
||||||
protected virtual void OnOutputChanged(string outputName) {
|
protected virtual void OnOutputChanged(string outputName) {
|
||||||
if (this.currentNucleus.parent != null)
|
if (this.currentNucleus.parent != null)
|
||||||
// Get nucleus in the parent instance
|
// Get nucleus in the parent instance
|
||||||
@ -86,6 +101,7 @@ namespace NanoBrain {
|
|||||||
this.currentNucleus = this.selectedOutput;
|
this.currentNucleus = this.selectedOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool subscribed = false;
|
bool subscribed = false;
|
||||||
void Subscribe() {
|
void Subscribe() {
|
||||||
if (subscribed) return;
|
if (subscribed) return;
|
||||||
@ -106,8 +122,8 @@ namespace NanoBrain {
|
|||||||
this.serializedBrain = new SerializedObject(this.prefab);
|
this.serializedBrain = new SerializedObject(this.prefab);
|
||||||
this.currentNucleus = nucleus;
|
this.currentNucleus = nucleus;
|
||||||
Rebuild(); //inspectorContainer);
|
Rebuild(); //inspectorContainer);
|
||||||
OnOutputChanged(outputsField.choices[0]);
|
if (outputsPopup != null)
|
||||||
|
OnOutputChanged(outputsPopup.choices[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rebuild() {
|
void Rebuild() {
|
||||||
@ -190,9 +206,10 @@ namespace NanoBrain {
|
|||||||
Handles.BeginGUI();
|
Handles.BeginGUI();
|
||||||
DrawGraph();
|
DrawGraph();
|
||||||
Handles.EndGUI();
|
Handles.EndGUI();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Graph
|
||||||
|
|
||||||
protected virtual void DrawGraph() {
|
protected virtual void DrawGraph() {
|
||||||
if (mode == Mode.Focus)
|
if (mode == Mode.Focus)
|
||||||
DrawFocusGraph();
|
DrawFocusGraph();
|
||||||
@ -200,6 +217,8 @@ namespace NanoBrain {
|
|||||||
DrawFullGraph();
|
DrawFullGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Full Graph
|
||||||
|
|
||||||
protected void DrawFullGraph() {
|
protected void DrawFullGraph() {
|
||||||
//Dag dag = GenerateGraph(this.prefab);
|
//Dag dag = GenerateGraph(this.prefab);
|
||||||
Dag dag = GenerateGraph(this.selectedOutput);
|
Dag dag = GenerateGraph(this.selectedOutput);
|
||||||
@ -219,6 +238,31 @@ namespace NanoBrain {
|
|||||||
// Draw nodes
|
// Draw nodes
|
||||||
foreach (DagNode n in dag.nodes)
|
foreach (DagNode n in dag.nodes)
|
||||||
DrawNucleus(n.nucleus, n.position, 1, n.radius);
|
DrawNucleus(n.nucleus, n.position, 1, n.radius);
|
||||||
|
|
||||||
|
// Determine graph width
|
||||||
|
float width = 0;
|
||||||
|
float currentNucleusPosition = 0;
|
||||||
|
foreach (DagNode node in dag.nodes) {
|
||||||
|
if (node.position.x > width)
|
||||||
|
width = node.position.x;
|
||||||
|
if (node.nucleus == currentNucleus)
|
||||||
|
currentNucleusPosition = node.position.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize the graph container to the full graph width
|
||||||
|
float margin = 50f;
|
||||||
|
graphContainer.style.width = width + 2 * margin;
|
||||||
|
|
||||||
|
// Scroll to the current nucleus
|
||||||
|
float viewportWidth = scrollView.layout.width;
|
||||||
|
// center currentNucleus in viewport
|
||||||
|
float desiredScrollX = currentNucleusPosition - viewportWidth * 0.5f;
|
||||||
|
// clamp between 0 and maximum scrollable range
|
||||||
|
float maxScrollX = Mathf.Max(0f, graphContainer.resolvedStyle.width - viewportWidth);
|
||||||
|
desiredScrollX = Mathf.Clamp(desiredScrollX, 0f, maxScrollX);
|
||||||
|
|
||||||
|
Vector2 current = scrollView.scrollOffset;
|
||||||
|
scrollView.scrollOffset = new Vector2(desiredScrollX, current.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dag GenerateGraph(Nucleus rootNucleus) {
|
public Dag GenerateGraph(Nucleus rootNucleus) {
|
||||||
@ -258,6 +302,10 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Full Graph
|
||||||
|
|
||||||
|
#region Focus Graph
|
||||||
|
|
||||||
protected void DrawFocusGraph() {
|
protected void DrawFocusGraph() {
|
||||||
float size = 20;
|
float size = 20;
|
||||||
Vector3 position = new(150, 210, 0);
|
Vector3 position = new(150, 210, 0);
|
||||||
@ -334,6 +382,7 @@ namespace NanoBrain {
|
|||||||
maxValue = cluster.defaultOutput.outputMagnitude;
|
maxValue = cluster.defaultOutput.outputMagnitude;
|
||||||
DrawNucleus(this.currentNucleus, position, maxValue, 20);
|
DrawNucleus(this.currentNucleus, position, maxValue, 20);
|
||||||
}
|
}
|
||||||
|
graphContainer.style.width = 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) {
|
private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) {
|
||||||
@ -455,6 +504,8 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Focus Graph
|
||||||
|
|
||||||
protected void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) {
|
protected void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) {
|
||||||
Color color;
|
Color color;
|
||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
@ -647,19 +698,7 @@ namespace NanoBrain {
|
|||||||
Handles.DrawLine(from, to);
|
Handles.DrawLine(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
// protected void DrawNode(Vector2 position, float size) {
|
#endregion Graph
|
||||||
// Handles.color = Color.black * 0.9f;
|
|
||||||
// Handles.DrawSolidDisc(position, Vector3.forward, size);
|
|
||||||
|
|
||||||
// Handles.color = Color.white;
|
|
||||||
// GUIStyle style = new(EditorStyles.label) {
|
|
||||||
// alignment = TextAnchor.UpperCenter,
|
|
||||||
// normal = { textColor = Color.white },
|
|
||||||
// fontStyle = FontStyle.Bold,
|
|
||||||
// };
|
|
||||||
// Vector3 labelPos = position - Vector3.down * (size + 10f); // below disc along up axis
|
|
||||||
// Handles.Label(labelPos, n.title, style);
|
|
||||||
// }
|
|
||||||
|
|
||||||
void OnSceneGUI(SceneView sceneView) {
|
void OnSceneGUI(SceneView sceneView) {
|
||||||
if (this.gameObject != null) {
|
if (this.gameObject != null) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user