From 2711be76e03da97bc229acb275515eac83cd0173 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 3 Mar 2026 12:15:40 +0000
Subject: [PATCH] Add double-click state node to open per-state sub-graph tab
- GetLayerName: also match _StateResult nodes for per-state layer naming
- PrefixStateMachineLayerNames: per-state layers get 3-level path prefix
(e.g., "AnimGraph > Locomotion > Idle")
- TryOpenSubGraph: state nodes navigate to per-state sub-graph layer
Co-authored-by: LoogLong <86428208+LoogLong@users.noreply.github.com>
---
FModel/ViewModels/AnimGraphViewModel.cs | 16 ++++++++++++----
FModel/Views/AnimGraphViewer.xaml.cs | 8 ++++----
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/FModel/ViewModels/AnimGraphViewModel.cs b/FModel/ViewModels/AnimGraphViewModel.cs
index 746212e8..4da8f3bc 100644
--- a/FModel/ViewModels/AnimGraphViewModel.cs
+++ b/FModel/ViewModels/AnimGraphViewModel.cs
@@ -239,8 +239,8 @@ public class AnimGraphViewModel
///
/// Renames state machine internal layers with a parent path prefix
- /// (e.g., "AnimGraph > Locomotion") to avoid name collisions with
- /// linked anim layer sub-graphs that may share the same base name.
+ /// (e.g., "AnimGraph > Locomotion" for the overview, or
+ /// "AnimGraph > Locomotion > Idle" for per-state sub-graphs).
///
private static void PrefixStateMachineLayerNames(AnimGraphViewModel vm)
{
@@ -272,7 +272,14 @@ public class AnimGraphViewModel
if (string.IsNullOrEmpty(smName))
continue;
- if (smParentLayer.TryGetValue(smName, out var parentName))
+ if (!smParentLayer.TryGetValue(smName, out var parentName))
+ continue;
+
+ // Per-state layers have a name different from the machine name
+ // (named after the StateResult node's Name property)
+ if (!layer.Name.Equals(smName, StringComparison.OrdinalIgnoreCase))
+ layer.Name = $"{parentName}{SubGraphPathSeparator}{smName}{SubGraphPathSeparator}{layer.Name}";
+ else
layer.Name = $"{parentName}{SubGraphPathSeparator}{smName}";
}
}
@@ -421,7 +428,8 @@ public class AnimGraphViewModel
private static string GetLayerName(List nodes, int index)
{
var rootNode = nodes.FirstOrDefault(n =>
- n.ExportType.EndsWith("_Root", StringComparison.OrdinalIgnoreCase) &&
+ (n.ExportType.EndsWith("_Root", StringComparison.OrdinalIgnoreCase) ||
+ n.ExportType.EndsWith("_StateResult", StringComparison.OrdinalIgnoreCase)) &&
n.AdditionalProperties.TryGetValue("Name", out _));
if (rootNode != null &&
rootNode.AdditionalProperties.TryGetValue("Name", out var rootName) &&
diff --git a/FModel/Views/AnimGraphViewer.xaml.cs b/FModel/Views/AnimGraphViewer.xaml.cs
index 3b9ce7aa..d4375367 100644
--- a/FModel/Views/AnimGraphViewer.xaml.cs
+++ b/FModel/Views/AnimGraphViewer.xaml.cs
@@ -563,10 +563,10 @@ public partial class AnimGraphViewer
}
else if (node.IsStateMachineState)
{
- // State nodes within an overview: try to open internal per-state layer
- // Internal layers share the state machine's path prefix name
- // (future: individual state layers could be opened here)
- return;
+ // State nodes within an overview: open the per-state internal sub-graph
+ // Per-state layers are named "overviewPath > stateName"
+ var overviewName = _currentLayerState?.Layer.Name ?? string.Empty;
+ layerName = $"{overviewName}{AnimGraphViewModel.SubGraphPathSeparator}{node.Name}";
}
else if (node.ExportType.Contains("StateMachine", StringComparison.OrdinalIgnoreCase))
{