diff --git a/Packages/nadena.dev.modular-avatar/Editor/Inspector/AvMenuTreeView.cs b/Packages/nadena.dev.modular-avatar/Editor/Inspector/AvMenuTreeView.cs index e136c9f8..b3ee28c2 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/Inspector/AvMenuTreeView.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/Inspector/AvMenuTreeView.cs @@ -23,6 +23,12 @@ namespace nadena.dev.modular_avatar.core.editor set => _treeView.Avatar = value; } + public ModularAvatarMenuInstaller Installer + { + get => _treeView.Installer; + set => _treeView.Installer = value; + } + public Action OnMenuSelected = (menu) => { }; private void Awake() @@ -53,12 +59,13 @@ namespace nadena.dev.modular_avatar.core.editor _treeView.OnGUI(new Rect(0, 0, position.width, position.height)); } - internal static void Show(VRCAvatarDescriptor Avatar, Action OnSelect) + internal static void Show(VRCAvatarDescriptor Avatar, ModularAvatarMenuInstaller Installer, Action OnSelect) { var window = GetWindow(); window.titleContent = new GUIContent("Select menu"); window.Avatar = Avatar; + window.Installer = Installer; window.OnMenuSelected = OnSelect; window.Show(); @@ -79,6 +86,18 @@ namespace nadena.dev.modular_avatar.core.editor } } + private ModularAvatarMenuInstaller _installer; + + public ModularAvatarMenuInstaller Installer + { + get => _installer; + set + { + _installer = value; + Reload(); + } + } + internal Action OnSelect = (menu) => { }; internal Action OnDoubleclickSelect = () => { }; @@ -106,21 +125,20 @@ namespace nadena.dev.modular_avatar.core.editor protected override TreeViewItem BuildRoot() { this._menuItems.Clear(); this._visitedMenuStack.Clear(); - - if (Avatar.expressionsMenu == null) { - // TODO: nullの場合もツリーを表示できるように(Installerがあれば子もあるので) - return new TreeViewItem(0, -1, "No menu"); - } _menuTree = new MenuTree(Avatar); _menuTree.AvatarsMenuMapping(); + foreach (ModularAvatarMenuInstaller installer in this.Avatar.gameObject.GetComponentsInChildren()) { + if (installer == Installer) continue; + this._menuTree.MappingMenuInstaller(installer); + } var root = new TreeViewItem(-1, -1, ""); List treeItems = new List { new TreeViewItem { id = 0, depth = 0, - displayName = $"{Avatar.gameObject.name} ({Avatar.expressionsMenu.name})" + displayName = $"{Avatar.gameObject.name} ({(Avatar.expressionsMenu == null ? "None" : Avatar.expressionsMenu.name)})" } }; this._menuItems.Add(Avatar.expressionsMenu); @@ -132,19 +150,19 @@ namespace nadena.dev.modular_avatar.core.editor } private void TraverseMenu(int depth, List items, VRCExpressionsMenu menu) { - IEnumerable children = this._menuTree.GetChildren(menu) - .Where(child => !this._visitedMenuStack.Contains(child)); - foreach (VRCExpressionsMenu child in children) { + IEnumerable> children = this._menuTree.GetChildren(menu) + .Where(child => !this._visitedMenuStack.Contains(child.Value)); + foreach (KeyValuePair child in children) { items.Add( new TreeViewItem { id = items.Count, depth = depth, - displayName = $"{ /*control.name*/null} ({child.name})" // TODO: サブメニュー名を取ってこれるように + displayName = $"{child.Key} ({child.Value.name})" } ); - this._menuItems.Add(child); - this._visitedMenuStack.Push(child); - this.TraverseMenu(depth + 1, items, child); + this._menuItems.Add(child.Value); + this._visitedMenuStack.Push(child.Value); + this.TraverseMenu(depth + 1, items, child.Value); this._visitedMenuStack.Pop(); } } diff --git a/Packages/nadena.dev.modular-avatar/Editor/Inspector/MenuInstallerEditor.cs b/Packages/nadena.dev.modular-avatar/Editor/Inspector/MenuInstallerEditor.cs index 0cf1afda..d93b11c1 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/Inspector/MenuInstallerEditor.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/Inspector/MenuInstallerEditor.cs @@ -86,7 +86,7 @@ namespace nadena.dev.modular_avatar.core.editor { if (installTargetType == InstallTargetType.VRCExpressionMenu) { - AvMenuTreeViewWindow.Show(avatar, menu => + AvMenuTreeViewWindow.Show(avatar, _installer, menu => { installTargetProperty.objectReferenceValue = menu; serializedObject.ApplyModifiedProperties(); diff --git a/Packages/nadena.dev.modular-avatar/Editor/Inspector/SubMenuCreatorEditor.cs b/Packages/nadena.dev.modular-avatar/Editor/Inspector/SubMenuCreatorEditor.cs index bf1fe54a..8c5d50ce 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/Inspector/SubMenuCreatorEditor.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/Inspector/SubMenuCreatorEditor.cs @@ -48,7 +48,7 @@ namespace nadena.dev.modular_avatar.core.editor { VRCAvatarDescriptor avatar = RuntimeUtil.FindAvatarInParents(this._creator.transform); if (avatar != null && GUILayout.Button(Localization.G("menuinstall.selectmenu"))) { if (installTargetType == InstallTargetType.VRCExpressionMenu) { - AvMenuTreeViewWindow.Show(avatar, menu => { + AvMenuTreeViewWindow.Show(avatar, null, menu => { installTargetProperty.objectReferenceValue = menu; serializedObject.ApplyModifiedProperties(); }); diff --git a/Packages/nadena.dev.modular-avatar/Editor/MenuTree.cs b/Packages/nadena.dev.modular-avatar/Editor/MenuTree.cs index 191dfc43..f0eeffee 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/MenuTree.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/MenuTree.cs @@ -11,14 +11,14 @@ namespace nadena.dev.modular_avatar.core.editor { public class MenuTree { private readonly VRCExpressionsMenu _rootMenu; private readonly HashSet _included; - private readonly Dictionary> _childrenMap; + private readonly Dictionary>> _childrenMap; private readonly Dictionary> _flashedChildrenMap; public MenuTree(VRCAvatarDescriptor descriptor) { this._rootMenu = descriptor.expressionsMenu; this._included = new HashSet(); - this._childrenMap = new Dictionary>(); + this._childrenMap = new Dictionary>>(); if (this._rootMenu == null) { this._rootMenu = ScriptableObject.CreateInstance(); @@ -32,17 +32,19 @@ namespace nadena.dev.modular_avatar.core.editor { this.MappingMenu(this._rootMenu); } - public void AddMenuInstaller(ModularAvatarMenuInstaller installer) { + public void MappingMenuInstaller(ModularAvatarMenuInstaller installer) { if (installer.menuToAppend == null) return; VRCExpressionsMenu parent = installer.installTargetMenu; if (parent == null) parent = this._rootMenu; this.MappingMenu(installer.menuToAppend, parent); } - public IEnumerable GetChildren(VRCExpressionsMenu parent) { + public IEnumerable> GetChildren(VRCExpressionsMenu parent) { // TODO: ライブラリとするのであれば、複製したリスト or ImmutableArray,を返すのが好ましい if (parent == null) parent = this._rootMenu; - return this._childrenMap.TryGetValue(parent, out List children) ? children : Enumerable.Empty(); + return this._childrenMap.TryGetValue(parent, out List> children) + ? children + : Enumerable.Empty>(); } private void MappingMenu(VRCExpressionsMenu root, VRCExpressionsMenu customParent = null) { @@ -51,29 +53,30 @@ namespace nadena.dev.modular_avatar.core.editor { while (queue.Count > 0) { VRCExpressionsMenu parent = queue.Dequeue(); - IEnumerable subMenus = GetSubMenus(parent); + IEnumerable> subMenus = GetSubMenus(parent); if (customParent != null) { parent = customParent; customParent = null; } - foreach (VRCExpressionsMenu subMenu in subMenus) { - if (!this._childrenMap.TryGetValue(parent, out List children)) { - children = new List(); + + foreach (KeyValuePair subMenu in subMenus) { + if (!this._childrenMap.TryGetValue(parent, out List> children)) { + children = new List>(); this._childrenMap[parent] = children; } children.Add(subMenu); - if (this._included.Contains(subMenu)) continue; - queue.Enqueue(subMenu); - this._included.Add(subMenu); + if (this._included.Contains(subMenu.Value)) continue; + queue.Enqueue(subMenu.Value); + this._included.Add(subMenu.Value); } } } - private static IEnumerable GetSubMenus(VRCExpressionsMenu expressionsMenu) { + private static IEnumerable> GetSubMenus(VRCExpressionsMenu expressionsMenu) { return expressionsMenu.controls .Where(control => control.type == ControlType.SubMenu && control.subMenu != null) - .Select(control => control.subMenu); + .Select(control => new KeyValuePair(control.name, control.subMenu)); } } } \ No newline at end of file