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)) {