Files
FlaxEngine/Source/Editor/Surface/Elements/SkeletonNodeNameSelectElement.cs
2024-02-26 19:00:48 +01:00

128 lines
4.1 KiB
C#

// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Text;
using FlaxEngine;
namespace FlaxEditor.Surface.Elements
{
/// <summary>
/// The Visject surface node element used to pick a skeleton node name with a combo box.
/// </summary>
[HideInEditor]
public class SkeletonNodeNameSelectElement : ComboBoxElement
{
private readonly Dictionary<string, int> _nodeNameToIndex = new Dictionary<string, int>();
/// <summary>
/// Gets or sets the name of the selected node.
/// </summary>
public string SelectedNodeName
{
get
{
var selectedIndex = SelectedIndex;
foreach (var e in _nodeNameToIndex)
{
if (e.Value == selectedIndex)
return e.Key;
}
return string.Empty;
}
set
{
if (!string.IsNullOrEmpty(value) && _nodeNameToIndex.TryGetValue(value, out var index))
SelectedIndex = index;
else
SelectedIndex = -1;
}
}
/// <inheritdoc />
public SkeletonNodeNameSelectElement(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(parentNode, archetype)
{
_isAutoSelect = true;
if (Surface == null)
return;
UpdateComboBox();
// Select saved value
_selectedIndices.Clear();
if (Archetype.ValueIndex != -1)
{
SelectedNodeName = (string)ParentNode.Values[Archetype.ValueIndex];
ParentNode.ValuesChanged += OnNodeValuesChanged;
}
}
private void OnNodeValuesChanged()
{
_selectedIndices.Clear();
var selectedNode = (string)ParentNode.Values[Archetype.ValueIndex];
if (!string.IsNullOrEmpty(selectedNode) && _nodeNameToIndex.TryGetValue(selectedNode, out var index))
_selectedIndices.Add(index);
OnSelectedIndexChanged();
}
/// <summary>
/// Updates the Combo Box items list from the current skeleton nodes hierarchy.
/// </summary>
protected void UpdateComboBox()
{
// Prepare
var selectedNode = SelectedNodeName;
_items.Clear();
_nodeNameToIndex.Clear();
// Get the skeleton
var surfaceParam = Surface.GetParameter(Windows.Assets.AnimationGraphWindow.BaseModelId);
var skeleton = surfaceParam != null ? FlaxEngine.Content.LoadAsync<SkinnedModel>((Guid)surfaceParam.Value) : null;
if (skeleton == null || skeleton.WaitForLoaded())
{
SelectedIndex = -1;
return;
}
// Update the items
var nodes = skeleton.Nodes;
_items.Capacity = Mathf.Max(_items.Capacity, nodes.Length);
var sb = new StringBuilder(64);
for (int nodeIndex = 0; nodeIndex < nodes.Length; nodeIndex++)
{
sb.Clear();
var node = nodes[nodeIndex];
_nodeNameToIndex[node.Name] = nodeIndex;
int parent = node.ParentIndex;
while (parent != -1)
{
sb.Append(" ");
parent = nodes[parent].ParentIndex;
}
sb.Append("> ");
sb.Append(node.Name);
_items.Add(sb.ToString());
}
// Restore the selected node
SelectedNodeName = selectedNode;
}
/// <inheritdoc />
protected override void OnSelectedIndexChanged()
{
if ((string)ParentNode.Values[Archetype.ValueIndex] != SelectedNodeName)
{
// Edit value
ParentNode.SetValue(Archetype.ValueIndex, SelectedNodeName);
}
//base.OnSelectedIndexChanged();
}
}
}