From 1052c42a47fe8a3ebee48aed761d6ddc982eb2eb Mon Sep 17 00:00:00 2001 From: muhammadIdhamMaarif Date: Mon, 15 Sep 2025 05:35:29 +0700 Subject: [PATCH] Migrate MuscleInspectorEditor to generic IMGUI TreeView API (Unity 6000) & fix RowGUIArgs usage - Replace obsolete TreeView/TreeViewItem/TreeViewState with generic counterparts - Correct RowGUI signature to use nested non-generic TreeView.RowGUIArgs - Implement IEnumerable to avoid NotImplementedException - Use Mathf.Approximately for stable muscle slider updates - Initialize TreeViewState on enable --- .../UniHumanoid/MuscleInspectorEditor.cs | 155 +++++++----------- 1 file changed, 59 insertions(+), 96 deletions(-) diff --git a/Assets/UniGLTF/Editor/UniHumanoid/MuscleInspectorEditor.cs b/Assets/UniGLTF/Editor/UniHumanoid/MuscleInspectorEditor.cs index d0fb62f2b..45108ca9b 100644 --- a/Assets/UniGLTF/Editor/UniHumanoid/MuscleInspectorEditor.cs +++ b/Assets/UniGLTF/Editor/UniHumanoid/MuscleInspectorEditor.cs @@ -1,20 +1,16 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; -using System.Linq; using UnityEditor; using UnityEditor.IMGUI.Controls; using UnityEngine; - namespace UniHumanoid { class BoneNode : IEnumerable { public HumanBodyBones Bone { get; private set; } - public List Children = new List(); - public int[] Muscles; public BoneNode(HumanBodyBones bone, params int[] muscles) @@ -25,45 +21,33 @@ namespace UniHumanoid public IEnumerator GetEnumerator() { - throw new NotImplementedException(); + yield return this; + foreach (var c in Children) + { + foreach (var n in c) yield return n; + } } - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public void Add(BoneNode child) - { - Children.Add(child); - } + public void Add(BoneNode child) => Children.Add(child); } - class BoneTreeViewItem : TreeViewItem + class BoneTreeViewItem : TreeViewItem { - //HumanBodyBones m_bone; - - public BoneTreeViewItem(int id, int depth, HumanBodyBones bone) : base(id, depth, bone.ToString()) - { - //m_bone = bone; - } + public BoneTreeViewItem(int id, int depth, HumanBodyBones bone) : base(id, depth, bone.ToString()) { } } - class MuscleTreeViewItem : TreeViewItem + class MuscleTreeViewItem : TreeViewItem { - public int Muscle - { - get; - private set; - } - + public int Muscle { get; private set; } public MuscleTreeViewItem(int id, int depth, int muscle) : base(id, depth, HumanTrait.MuscleName[muscle]) { Muscle = muscle; } } - class BoneTreeView : TreeView + class BoneTreeView : TreeView { static BoneNode Skeleton = new BoneNode(HumanBodyBones.Hips) { @@ -109,10 +93,8 @@ namespace UniHumanoid } }; - //Animator m_animator; HumanPoseHandler m_handler; HumanPose m_pose; - bool m_updated; public void Begin() @@ -129,24 +111,21 @@ namespace UniHumanoid m_updated = false; } - public BoneTreeView(TreeViewState treeViewState, MultiColumnHeader header, HumanPoseHandler handler) + public BoneTreeView(TreeViewState treeViewState, MultiColumnHeader header, HumanPoseHandler handler) : base(treeViewState, header) { m_handler = handler; Reload(); } - protected override TreeViewItem BuildRoot() + protected override TreeViewItem BuildRoot() { - return new TreeViewItem { id = 0, depth = -1 }; + return new TreeViewItem { id = 0, depth = -1 }; } - protected override IList BuildRows(TreeViewItem root) + protected override IList> BuildRows(TreeViewItem root) { - var rows = GetRows() ?? new List(200); - - // We use the GameObject instanceIDs as ids for items as we want to - // select the game objects and not the transform components. + var rows = GetRows() ?? new List>(200); rows.Clear(); var item = CreateTreeViewItemForBone(HumanBodyBones.Hips); @@ -163,14 +142,14 @@ namespace UniHumanoid } SetupDepthsFromParentsAndChildren(root); - return rows; } - void AddChildrenRecursive(BoneNode bone, TreeViewItem item, IList rows) + void AddChildrenRecursive(BoneNode bone, TreeViewItem item, IList> rows) { int childCount = bone.Children.Count; - item.children = new List(childCount); + item.children = new List>(childCount); + if (bone.Muscles != null) { foreach (var muscle in bone.Muscles) @@ -187,26 +166,24 @@ namespace UniHumanoid item.AddChild(childItem); rows.Add(childItem); - //if (child.Children.Count > 0) + if (IsExpanded(childItem.id)) { - if (IsExpanded(childItem.id)) - { - AddChildrenRecursive(child, childItem, rows); - } - else - { - childItem.children = CreateChildListForCollapsedParent(); - } + AddChildrenRecursive(child, childItem, rows); + } + else + { + childItem.children = CreateChildListForCollapsedParent(); } } } - static TreeViewItem CreateTreeViewItemForBone(HumanBodyBones bone) + static TreeViewItem CreateTreeViewItemForBone(HumanBodyBones bone) { - return new TreeViewItem((int)bone, -1, Enum.GetName(typeof(HumanBodyBones), bone)); + return new BoneTreeViewItem((int)bone, -1, bone); } - protected override void RowGUI(RowGUIArgs args) + // inside class BoneTreeView : TreeView + protected override void RowGUI(UnityEditor.IMGUI.Controls.TreeView.RowGUIArgs args) { for (int i = 0; i < args.GetNumVisibleColumns(); ++i) { @@ -214,41 +191,33 @@ namespace UniHumanoid } } - void CellGUI(Rect cellRect, int index, ref RowGUIArgs args) + void CellGUI(Rect cellRect, int index, ref UnityEditor.IMGUI.Controls.TreeView.RowGUIArgs args) { - // Center cell rect vertically (makes it easier to place controls, icons etc in the cells) CenterRectUsingSingleLineHeight(ref cellRect); switch (index) { case 0: - { - // Default icon and label - args.rowRect = cellRect; - base.RowGUI(args); - } + { + args.rowRect = cellRect; + base.RowGUI(args); break; - + } case 1: + { + if (args.item is MuscleTreeViewItem muscleItem) { - var muscleItem = args.item as MuscleTreeViewItem; - if (muscleItem != null) + var muscleIndex = muscleItem.Muscle; + var muscles = m_pose.muscles; + var value = EditorGUI.Slider(cellRect, GUIContent.none, muscles[muscleIndex], -1f, 1f); + if (!Mathf.Approximately(value, muscles[muscleIndex])) { - var muscleIndex = muscleItem.Muscle; - var muscles = m_pose.muscles; - var value = EditorGUI.Slider(cellRect, GUIContent.none, muscles[muscleIndex], -1f, 1f); - if (value != muscles[muscleIndex]) - { - muscles[muscleIndex] = value; - m_updated = true; - } - } - else - { - + muscles[muscleIndex] = value; + m_updated = true; } } break; + } } } @@ -278,32 +247,24 @@ namespace UniHumanoid } } - [CustomEditor(typeof(MuscleInspector))] public class MuscleInspectorEditor : Editor { [NonSerialized] bool m_Initialized; - [SerializeField] TreeViewState m_TreeViewState; // Serialized in the window layout file so it survives assembly reloading - //[SerializeField] MultiColumnHeaderState m_MultiColumnHeaderState; + + // Note: Unity 6000 recommends generic state. It's fine if this isn't serialized by Unity's object serializer; + // the TreeView manages its own persistence in editor layouts. + [SerializeField] TreeViewState m_TreeViewState; + SearchField m_SearchField; BoneTreeView m_TreeView; MuscleInspector m_target; HumanPoseHandler m_handler; - MultiColumnHeader GetHeaderState() { - //bool firstInit = m_MultiColumnHeaderState == null; - var headerState = BoneTreeView.CreateDefaultMultiColumnHeaderState(); - /* - if (MultiColumnHeaderState.CanOverwriteSerializedFields(m_MultiColumnHeaderState, headerState)) - { - MultiColumnHeaderState.OverwriteSerializedFields(m_MultiColumnHeaderState, headerState); - } - m_MultiColumnHeaderState = headerState; - */ var multiColumnHeader = new MultiColumnHeader(headerState); multiColumnHeader.ResizeToFit(); return multiColumnHeader; @@ -311,17 +272,19 @@ namespace UniHumanoid void OnEnable() { - var mi = this.target as MuscleInspector; - if (mi.TryGetComponent(out var animator) - && animator.avatar != null - && animator.avatar.isValid - && animator.avatar.isHuman - ) + var mi = target as MuscleInspector; + if (mi != null && + mi.TryGetComponent(out var animator) && + animator.avatar != null && + animator.avatar.isValid && + animator.avatar.isHuman) { UniGLTF.UniGLTFLogger.Log("MuscleInspectorEditor.OnEnable"); m_handler = new HumanPoseHandler(animator.avatar, animator.transform); - m_TreeView = new BoneTreeView(new TreeViewState(), GetHeaderState(), m_handler); + // Use existing state if available, else create a new one + if (m_TreeViewState == null) m_TreeViewState = new TreeViewState(); + m_TreeView = new BoneTreeView(m_TreeViewState, GetHeaderState(), m_handler); } }