mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-05-14 15:19:11 +08:00
ToggleGroup UI
This commit is contained in:
parent
64d831672a
commit
f2ef8099b0
@ -81,10 +81,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
protected virtual VisualElement CreateInnerInspectorGUI()
|
||||
{
|
||||
var throwaway = new InspectorElement();
|
||||
MethodInfo m = typeof(InspectorElement).GetMethod("CreateIMGUIInspectorFromEditor",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
return m.Invoke(throwaway, new object[] {serializedObject, this, false}) as VisualElement;
|
||||
return null;
|
||||
}
|
||||
|
||||
public sealed override VisualElement CreateInspectorGUI()
|
||||
@ -94,10 +91,19 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
var inner = CreateInnerInspectorGUI();
|
||||
|
||||
bool innerIsImgui = (inner == null);
|
||||
if (innerIsImgui)
|
||||
{
|
||||
var throwaway = new InspectorElement();
|
||||
MethodInfo m = typeof(InspectorElement).GetMethod("CreateIMGUIInspectorFromEditor",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
inner = m.Invoke(throwaway, new object[] {serializedObject, this, false}) as VisualElement;
|
||||
}
|
||||
|
||||
_visualElement = new MAVisualElement();
|
||||
_visualElement.Add(inner);
|
||||
|
||||
_suppressOnceDefaultMargins = true;
|
||||
_suppressOnceDefaultMargins = innerIsImgui;
|
||||
return _visualElement;
|
||||
}
|
||||
|
||||
|
@ -7,69 +7,38 @@ using VRC.SDK3.Avatars.ScriptableObjects;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
internal class MenuPreviewGUI
|
||||
internal class MenuObjectHeader
|
||||
{
|
||||
private const float INDENT_PER_LEVEL = 2;
|
||||
private Action _redraw;
|
||||
private float _indentLevel = 0;
|
||||
private readonly Dictionary<object, Action> _guiNodes = new Dictionary<object, Action>();
|
||||
private static float _indentLevel = 0;
|
||||
|
||||
public MenuPreviewGUI(Action redraw)
|
||||
{
|
||||
_redraw = redraw;
|
||||
}
|
||||
|
||||
public void DoGUI(MenuSource root)
|
||||
{
|
||||
_indentLevel = 0;
|
||||
new VisitorContext(this).PushNode(root);
|
||||
}
|
||||
|
||||
public void DoGUI(ModularAvatarMenuInstaller root)
|
||||
{
|
||||
_indentLevel = 0;
|
||||
new VisitorContext(this).PushMenuInstaller(root);
|
||||
}
|
||||
|
||||
public void DoGUI(VRCExpressionsMenu menu, GameObject parameterReference = null)
|
||||
{
|
||||
_indentLevel = 0;
|
||||
new VisitorContext(this).PushNode(menu);
|
||||
}
|
||||
|
||||
private void PushGuiNode(object key, Func<Action> guiBuilder)
|
||||
{
|
||||
if (!_guiNodes.TryGetValue(key, out var gui))
|
||||
{
|
||||
gui = guiBuilder();
|
||||
_guiNodes.Add(key, gui);
|
||||
}
|
||||
|
||||
gui();
|
||||
}
|
||||
|
||||
private class Header
|
||||
{
|
||||
private MenuPreviewGUI _gui;
|
||||
private UnityEngine.Object _headerObj;
|
||||
private SerializedProperty _disableProp;
|
||||
|
||||
public Header(MenuPreviewGUI gui, UnityEngine.Object headerObj, SerializedProperty disableProp = null)
|
||||
public MenuObjectHeader(UnityEngine.Object headerObj, SerializedProperty disableProp = null)
|
||||
{
|
||||
_gui = gui;
|
||||
_headerObj = headerObj;
|
||||
_disableProp = disableProp;
|
||||
}
|
||||
|
||||
public static void ClearIndent()
|
||||
{
|
||||
_indentLevel = 0;
|
||||
}
|
||||
|
||||
public IDisposable Scope()
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(_gui._indentLevel);
|
||||
_gui._indentLevel += INDENT_PER_LEVEL;
|
||||
GUILayout.Space(_indentLevel);
|
||||
_indentLevel += INDENT_PER_LEVEL;
|
||||
|
||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
|
||||
if (_headerObj != null)
|
||||
{
|
||||
var oldIndent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
try
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
@ -91,28 +60,67 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorGUI.indentLevel = oldIndent;
|
||||
}
|
||||
}
|
||||
|
||||
return new ScopeSentinel(_gui);
|
||||
return new ScopeSentinel();
|
||||
}
|
||||
|
||||
private class ScopeSentinel : IDisposable
|
||||
{
|
||||
private readonly MenuPreviewGUI _gui;
|
||||
|
||||
public ScopeSentinel(MenuPreviewGUI gui)
|
||||
public ScopeSentinel()
|
||||
{
|
||||
_gui = gui;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GUILayout.EndVertical();
|
||||
_gui._indentLevel -= INDENT_PER_LEVEL;
|
||||
_indentLevel -= INDENT_PER_LEVEL;
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class MenuPreviewGUI
|
||||
{
|
||||
private Action _redraw;
|
||||
private readonly Dictionary<object, Action> _guiNodes = new Dictionary<object, Action>();
|
||||
|
||||
public MenuPreviewGUI(Action redraw)
|
||||
{
|
||||
_redraw = redraw;
|
||||
}
|
||||
|
||||
public void DoGUI(MenuSource root)
|
||||
{
|
||||
new VisitorContext(this).PushNode(root);
|
||||
}
|
||||
|
||||
public void DoGUI(ModularAvatarMenuInstaller root)
|
||||
{
|
||||
new VisitorContext(this).PushMenuInstaller(root);
|
||||
}
|
||||
|
||||
public void DoGUI(VRCExpressionsMenu menu, GameObject parameterReference = null)
|
||||
{
|
||||
new VisitorContext(this).PushNode(menu);
|
||||
}
|
||||
|
||||
private void PushGuiNode(object key, Func<Action> guiBuilder)
|
||||
{
|
||||
if (!_guiNodes.TryGetValue(key, out var gui))
|
||||
{
|
||||
gui = guiBuilder();
|
||||
_guiNodes.Add(key, gui);
|
||||
}
|
||||
|
||||
gui();
|
||||
}
|
||||
|
||||
|
||||
private class VisitorContext : NodeContext
|
||||
{
|
||||
private readonly HashSet<object> _visited = new HashSet<object>();
|
||||
@ -127,7 +135,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
_gui.PushGuiNode((expMenu, parameterReference), () =>
|
||||
{
|
||||
var header = new Header(_gui, expMenu);
|
||||
var header = new MenuObjectHeader(expMenu);
|
||||
var obj = new SerializedObject(expMenu);
|
||||
var controls = obj.FindProperty(nameof(expMenu.controls));
|
||||
var subGui = new List<MenuItemCoreGUI>();
|
||||
@ -143,7 +151,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
foreach (var gui in subGui)
|
||||
{
|
||||
using (new Header(_gui, null).Scope())
|
||||
using (new MenuObjectHeader(null).Scope())
|
||||
{
|
||||
gui.DoGUI();
|
||||
}
|
||||
@ -164,7 +172,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
_gui.PushGuiNode(item, () =>
|
||||
{
|
||||
var header = new Header(_gui, item,
|
||||
var header = new MenuObjectHeader(item,
|
||||
new SerializedObject(item.gameObject).FindProperty("m_IsActive"));
|
||||
var gui = new MenuItemCoreGUI(new SerializedObject(item), _gui._redraw);
|
||||
return () =>
|
||||
@ -178,7 +186,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
}
|
||||
else
|
||||
{
|
||||
using (new Header(_gui, source as UnityEngine.Object).Scope())
|
||||
using (new MenuObjectHeader(source as UnityEngine.Object).Scope())
|
||||
{
|
||||
if (_visited.Contains(source)) return;
|
||||
_visited.Add(source);
|
||||
@ -190,7 +198,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
public void PushNode(ModularAvatarMenuInstaller installer)
|
||||
{
|
||||
using (new Header(_gui, installer).Scope())
|
||||
using (new MenuObjectHeader(installer).Scope())
|
||||
{
|
||||
PushMenuInstaller(installer);
|
||||
}
|
||||
|
@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
[CustomEditor(typeof(ToggleGroup))]
|
||||
internal class ToggleGroupInspector : MAEditorBase
|
||||
{
|
||||
private void OnEnable()
|
||||
{
|
||||
EditorApplication.hierarchyChanged += Invalidate;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
EditorApplication.hierarchyChanged -= Invalidate;
|
||||
}
|
||||
|
||||
private List<Action> _menuItemActions = null;
|
||||
|
||||
private void Invalidate()
|
||||
{
|
||||
var target = (ToggleGroup) this.target;
|
||||
var avatar = RuntimeUtil.FindAvatarInParents(target.transform);
|
||||
var menuItems = avatar.GetComponentsInChildren<ModularAvatarMenuItem>(true);
|
||||
|
||||
_menuItemActions = new List<Action>();
|
||||
foreach (var menuItem in menuItems.Where(item => item.toggleGroup == target))
|
||||
{
|
||||
var node = CreateMenuItemNode(menuItem);
|
||||
_menuItemActions.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
private Action CreateMenuItemNode(ModularAvatarMenuItem menuItem)
|
||||
{
|
||||
bool foldout = false;
|
||||
|
||||
var coreUI = new MenuItemCoreGUI(new SerializedObject(menuItem), Repaint);
|
||||
var enableMenuItem = new SerializedObject(menuItem.gameObject).FindProperty("m_IsActive");
|
||||
|
||||
List<Action> foldoutInspectors = null;
|
||||
|
||||
return () =>
|
||||
{
|
||||
using (new MenuObjectHeader(menuItem, enableMenuItem).Scope())
|
||||
{
|
||||
coreUI.DoGUI();
|
||||
|
||||
foldout = EditorGUILayout.Foldout(foldout, "Actions");
|
||||
if (foldout)
|
||||
{
|
||||
if (foldoutInspectors == null)
|
||||
{
|
||||
foldoutInspectors = menuItem.GetComponents<MenuAction>()
|
||||
.Select(action =>
|
||||
{
|
||||
var component = (Component) action;
|
||||
var editor = CreateEditor(component);
|
||||
var enabled_prop = new SerializedObject(component).FindProperty("m_Enabled");
|
||||
|
||||
return (Action) (() =>
|
||||
{
|
||||
using (new MenuObjectHeader(component, enabled_prop).Scope())
|
||||
{
|
||||
editor.OnInspectorGUI();
|
||||
}
|
||||
});
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
foreach (var inspector in foldoutInspectors)
|
||||
{
|
||||
inspector();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnInnerInspectorGUI()
|
||||
{
|
||||
if (_menuItemActions == null) Invalidate();
|
||||
|
||||
EditorGUILayout.LabelField("Bound menu items", EditorStyles.boldLabel);
|
||||
foreach (var action in _menuItemActions)
|
||||
{
|
||||
try
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
action();
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 357527439f084cd6812d6e5dcd9692f8
|
||||
timeCreated: 1677595893
|
Loading…
x
Reference in New Issue
Block a user