2022-10-05 08:34:04 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2023-01-02 15:42:54 +08:00
|
|
|
|
using System.Linq;
|
2022-10-05 08:34:04 +08:00
|
|
|
|
using NUnit.Framework;
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
using UnityEditor.IMGUI.Controls;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using VRC.SDK3.Avatars.Components;
|
|
|
|
|
using VRC.SDK3.Avatars.ScriptableObjects;
|
|
|
|
|
using VRC.SDKBase;
|
|
|
|
|
|
2022-11-11 12:39:58 +08:00
|
|
|
|
namespace nadena.dev.modular_avatar.core.editor
|
2022-10-05 08:34:04 +08:00
|
|
|
|
{
|
|
|
|
|
class AvMenuTreeViewWindow : EditorWindow
|
|
|
|
|
{
|
|
|
|
|
private VRCAvatarDescriptor _avatarDescriptor;
|
|
|
|
|
private AvMenuTreeView _treeView;
|
|
|
|
|
|
|
|
|
|
public VRCAvatarDescriptor Avatar
|
|
|
|
|
{
|
|
|
|
|
get => _treeView.Avatar;
|
|
|
|
|
set => _treeView.Avatar = value;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-02 15:42:54 +08:00
|
|
|
|
public ModularAvatarMenuInstaller TargetInstaller
|
|
|
|
|
{
|
|
|
|
|
get => _treeView.TargetInstaller;
|
|
|
|
|
set => _treeView.TargetInstaller = value;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 08:34:04 +08:00
|
|
|
|
public Action<VRCExpressionsMenu> OnMenuSelected = (menu) => { };
|
|
|
|
|
|
|
|
|
|
private void Awake()
|
|
|
|
|
{
|
|
|
|
|
_treeView = new AvMenuTreeView(new TreeViewState());
|
|
|
|
|
_treeView.OnSelect = (menu) => OnMenuSelected.Invoke(menu);
|
|
|
|
|
_treeView.OnDoubleclickSelect = Close;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-01 04:40:10 +08:00
|
|
|
|
private void OnLostFocus()
|
|
|
|
|
{
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 08:34:04 +08:00
|
|
|
|
private void OnDisable()
|
|
|
|
|
{
|
|
|
|
|
OnMenuSelected = (menu) => { };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnGUI()
|
|
|
|
|
{
|
|
|
|
|
if (_treeView == null || _treeView.Avatar == null)
|
|
|
|
|
{
|
|
|
|
|
Close();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_treeView.OnGUI(new Rect(0, 0, position.width, position.height));
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-02 15:42:54 +08:00
|
|
|
|
internal static void Show(VRCAvatarDescriptor Avatar, ModularAvatarMenuInstaller Installer, Action<VRCExpressionsMenu> OnSelect)
|
2022-10-05 08:34:04 +08:00
|
|
|
|
{
|
|
|
|
|
var window = GetWindow<AvMenuTreeViewWindow>();
|
|
|
|
|
window.titleContent = new GUIContent("Select menu");
|
|
|
|
|
|
|
|
|
|
window.Avatar = Avatar;
|
2023-01-02 15:42:54 +08:00
|
|
|
|
window.TargetInstaller = Installer;
|
2022-10-05 08:34:04 +08:00
|
|
|
|
window.OnMenuSelected = OnSelect;
|
|
|
|
|
|
|
|
|
|
window.Show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class AvMenuTreeView : TreeView
|
|
|
|
|
{
|
|
|
|
|
private VRCAvatarDescriptor _avatar;
|
|
|
|
|
|
|
|
|
|
public VRCAvatarDescriptor Avatar
|
|
|
|
|
{
|
|
|
|
|
get => _avatar;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_avatar = value;
|
|
|
|
|
Reload();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-02 15:42:54 +08:00
|
|
|
|
private ModularAvatarMenuInstaller _targetInstaller;
|
|
|
|
|
|
|
|
|
|
public ModularAvatarMenuInstaller TargetInstaller
|
|
|
|
|
{
|
|
|
|
|
get => _targetInstaller;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_targetInstaller = value;
|
|
|
|
|
Reload();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 08:34:04 +08:00
|
|
|
|
internal Action<VRCExpressionsMenu> OnSelect = (menu) => { };
|
|
|
|
|
internal Action OnDoubleclickSelect = () => { };
|
|
|
|
|
|
|
|
|
|
private List<VRCExpressionsMenu> _menuItems = new List<VRCExpressionsMenu>();
|
|
|
|
|
private HashSet<VRCExpressionsMenu> _visitedMenus = new HashSet<VRCExpressionsMenu>();
|
|
|
|
|
|
2023-01-02 15:42:54 +08:00
|
|
|
|
private MenuTree _menuTree;
|
|
|
|
|
private Stack<VRCExpressionsMenu> _visitedMenuStack = new Stack<VRCExpressionsMenu>();
|
|
|
|
|
|
2022-10-05 08:34:04 +08:00
|
|
|
|
public AvMenuTreeView(TreeViewState state) : base(state)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void SelectionChanged(IList<int> selectedIds)
|
|
|
|
|
{
|
|
|
|
|
OnSelect.Invoke(_menuItems[selectedIds[0]]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void DoubleClickedItem(int id)
|
|
|
|
|
{
|
|
|
|
|
OnSelect.Invoke(_menuItems[id]);
|
|
|
|
|
OnDoubleclickSelect.Invoke();
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-02 15:42:54 +08:00
|
|
|
|
protected override TreeViewItem BuildRoot()
|
2022-10-05 08:34:04 +08:00
|
|
|
|
{
|
|
|
|
|
_menuItems.Clear();
|
2023-01-02 15:42:54 +08:00
|
|
|
|
_visitedMenuStack.Clear();
|
2022-10-05 08:34:04 +08:00
|
|
|
|
|
2023-01-02 15:42:54 +08:00
|
|
|
|
_menuTree = new MenuTree(Avatar);
|
|
|
|
|
_menuTree.TraverseAvatarMenu();
|
|
|
|
|
foreach (ModularAvatarMenuInstaller installer in Avatar.gameObject.GetComponentsInChildren<ModularAvatarMenuInstaller>(true))
|
2022-10-05 08:34:04 +08:00
|
|
|
|
{
|
2023-01-02 15:42:54 +08:00
|
|
|
|
if (installer == TargetInstaller) continue;
|
|
|
|
|
_menuTree.TraverseMenuInstaller(installer);
|
2022-10-05 08:34:04 +08:00
|
|
|
|
}
|
2023-01-02 15:42:54 +08:00
|
|
|
|
|
|
|
|
|
var root = new TreeViewItem(-1, -1, "<root>");
|
|
|
|
|
List<TreeViewItem> treeItems = new List<TreeViewItem>
|
|
|
|
|
{
|
|
|
|
|
new TreeViewItem
|
|
|
|
|
{
|
|
|
|
|
id = 0,
|
|
|
|
|
depth = 0,
|
|
|
|
|
displayName = $"{Avatar.gameObject.name} ({(Avatar.expressionsMenu == null ? "None" : Avatar.expressionsMenu.name)})"
|
|
|
|
|
}
|
|
|
|
|
};
|
2022-10-05 08:34:04 +08:00
|
|
|
|
_menuItems.Add(Avatar.expressionsMenu);
|
2023-01-02 15:42:54 +08:00
|
|
|
|
_visitedMenuStack.Push(Avatar.expressionsMenu);
|
|
|
|
|
|
2022-10-05 08:34:04 +08:00
|
|
|
|
TraverseMenu(1, treeItems, Avatar.expressionsMenu);
|
|
|
|
|
SetupParentsAndChildrenFromDepths(root, treeItems);
|
|
|
|
|
return root;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-02 15:42:54 +08:00
|
|
|
|
private void TraverseMenu(int depth, List<TreeViewItem> items, VRCExpressionsMenu menu)
|
2022-10-05 08:34:04 +08:00
|
|
|
|
{
|
2023-01-02 15:42:54 +08:00
|
|
|
|
IEnumerable<MenuTree.ChildElement> children = _menuTree.GetChildren(menu)
|
|
|
|
|
.Where(child => !_visitedMenuStack.Contains(child.menu));
|
|
|
|
|
foreach (MenuTree.ChildElement child in children)
|
2022-10-05 08:34:04 +08:00
|
|
|
|
{
|
2023-01-02 15:42:54 +08:00
|
|
|
|
if (child.menu == null) continue;
|
|
|
|
|
string displayName = child.installer == null ?
|
|
|
|
|
$"{child.menuName} ({child.menu.name})" :
|
|
|
|
|
$"{child.menuName} ({child.menu.name}) InstallerObject : {child.installer.name}";
|
|
|
|
|
items.Add(
|
|
|
|
|
new TreeViewItem
|
2022-10-05 08:34:04 +08:00
|
|
|
|
{
|
2023-01-02 15:42:54 +08:00
|
|
|
|
id = items.Count,
|
2022-10-05 08:34:04 +08:00
|
|
|
|
depth = depth,
|
2023-01-02 15:42:54 +08:00
|
|
|
|
displayName = displayName
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
_menuItems.Add(child.menu);
|
|
|
|
|
_visitedMenuStack.Push(child.menu);
|
|
|
|
|
TraverseMenu(depth + 1, items, child.menu);
|
|
|
|
|
_visitedMenuStack.Pop();
|
2022-10-05 08:34:04 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|