mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-01-17 11:50:11 +08:00
ui: presets menu
This commit is contained in:
parent
ab529dc936
commit
ababe2e80a
@ -1,4 +1,11 @@
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using nadena.dev.modular_avatar.core.editor.menu;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VRC.Core;
|
||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||
using static nadena.dev.modular_avatar.core.editor.Localization;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
@ -7,24 +14,148 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
[CanEditMultipleObjects]
|
||||
internal class MAMenuItemInspector : MAEditorBase
|
||||
{
|
||||
private VRCExpressionsMenu MENU_CLOTHING;
|
||||
private ControlGroup CONTROL_GROUP_CLOTHING;
|
||||
|
||||
private List<(GUIContent, Action)> _presets = new List<(GUIContent, Action)>();
|
||||
private MenuItemCoreGUI _coreGUI;
|
||||
|
||||
private long _cacheSeq = -1;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
_coreGUI = new MenuItemCoreGUI(serializedObject, Repaint);
|
||||
_coreGUI.AlwaysExpandContents = true;
|
||||
|
||||
MENU_CLOTHING = Util.LoadAssetByGuid<VRCExpressionsMenu>("2fe0aa7ecd6bc4443bade672c978f59d");
|
||||
CONTROL_GROUP_CLOTHING
|
||||
= Util.LoadAssetByGuid<GameObject>("e451e988456f35b49a3d011d780bda07")
|
||||
?.GetComponent<ControlGroup>();
|
||||
|
||||
RebuildPresets();
|
||||
}
|
||||
|
||||
private void RebuildPresets()
|
||||
{
|
||||
_presets.Clear();
|
||||
|
||||
_cacheSeq = VirtualMenu.CacheSequence;
|
||||
|
||||
if (targets.Length == 1)
|
||||
{
|
||||
ModularAvatarMenuItem item = (ModularAvatarMenuItem) target;
|
||||
if (item.GetComponent<ModularAvatarMenuInstaller>() == null
|
||||
&& item.GetComponent<MenuAction>() != null
|
||||
&& item.Control.type == VRCExpressionsMenu.Control.ControlType.Toggle
|
||||
&& item.controlGroup != CONTROL_GROUP_CLOTHING
|
||||
)
|
||||
{
|
||||
_presets.Add((new GUIContent("Configure as outfit toggle"), ConfigureOutfitToggle));
|
||||
}
|
||||
|
||||
if (item.Control.type == VRCExpressionsMenu.Control.ControlType.SubMenu
|
||||
&& item.MenuSource == SubmenuSource.Children)
|
||||
{
|
||||
_presets.Add((new GUIContent("Set items as exclusive toggles"), ConfigureExclusiveToggles));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureExclusiveToggles()
|
||||
{
|
||||
ModularAvatarMenuItem item = (ModularAvatarMenuItem) target;
|
||||
|
||||
var controlGroup = item.gameObject.GetComponent<ControlGroup>();
|
||||
if (controlGroup == null)
|
||||
{
|
||||
controlGroup = Undo.AddComponent<ControlGroup>(item.gameObject);
|
||||
}
|
||||
|
||||
var sourceObject = (item.menuSource_otherObjectChildren
|
||||
? item.menuSource_otherObjectChildren
|
||||
: item.gameObject).transform;
|
||||
|
||||
foreach (Transform t in sourceObject)
|
||||
{
|
||||
var subItem = t.GetComponent<ModularAvatarMenuItem>();
|
||||
if (subItem == null) continue;
|
||||
if (subItem.GetComponent<MenuAction>() == null) continue;
|
||||
|
||||
Undo.RecordObject(subItem, "Configure exclusive toggles");
|
||||
subItem.controlGroup = controlGroup;
|
||||
subItem.Control.type = VRCExpressionsMenu.Control.ControlType.Toggle;
|
||||
}
|
||||
|
||||
// Clear caches
|
||||
OnEnable();
|
||||
}
|
||||
|
||||
private void ConfigureOutfitToggle()
|
||||
{
|
||||
ModularAvatarMenuItem item = (ModularAvatarMenuItem) target;
|
||||
Undo.RecordObject(item, "Configure outfit toggle");
|
||||
item.controlGroup = CONTROL_GROUP_CLOTHING;
|
||||
|
||||
// Determine if the item is already registered in the virtual menu - if not, we need to install it
|
||||
var avatar = RuntimeUtil.FindAvatarInParents(item.transform);
|
||||
if (avatar != null)
|
||||
{
|
||||
VirtualMenu virtualMenu = VirtualMenu.ForAvatar(RuntimeUtil.FindAvatarInParents(item.transform));
|
||||
if (virtualMenu.ContainsNode(item)) return;
|
||||
}
|
||||
|
||||
var installer = item.gameObject.AddComponent<ModularAvatarMenuInstaller>();
|
||||
Undo.RegisterCreatedObjectUndo(installer, "Configure outfit toggle");
|
||||
installer.installTargetMenu = MENU_CLOTHING;
|
||||
|
||||
// Clear caches
|
||||
OnEnable();
|
||||
}
|
||||
|
||||
protected override void OnInnerInspectorGUI()
|
||||
{
|
||||
if (VirtualMenu.CacheSequence != _cacheSeq) RebuildPresets();
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
_coreGUI.DoGUI();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
ShowPresetsButton();
|
||||
|
||||
ShowLanguageUI();
|
||||
}
|
||||
|
||||
private void ShowPresetsButton()
|
||||
{
|
||||
if (_presets.Count == 0) return;
|
||||
|
||||
var style = EditorStyles.popup;
|
||||
var rect = EditorGUILayout.GetControlRect(true, 18f, style);
|
||||
var controlId = GUIUtility.GetControlID("MAPresetsButton".GetHashCode(), FocusType.Keyboard, rect);
|
||||
|
||||
rect.xMin += 2 * rect.width / 3;
|
||||
|
||||
if (GUI.Button(rect, new GUIContent("Presets"), EditorStyles.popup))
|
||||
{
|
||||
EditorUtility.DisplayCustomMenu(
|
||||
rect,
|
||||
_presets.Select(elem => elem.Item1).ToArray(),
|
||||
-1,
|
||||
(_userData, _options, _index) =>
|
||||
{
|
||||
if (_index >= 0 && _index < _presets.Count)
|
||||
{
|
||||
_presets[_index].Item2();
|
||||
|
||||
RebuildPresets();
|
||||
}
|
||||
},
|
||||
controlId
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ModularAvatarMenuGroup))]
|
||||
|
@ -49,6 +49,8 @@ namespace nadena.dev.modular_avatar.core.editor.menu
|
||||
|
||||
private Action<VRCExpressionsMenu.Control> _currentPostprocessor = _control => { };
|
||||
|
||||
internal ImmutableHashSet<object> Visited => _visited.ToImmutableHashSet();
|
||||
|
||||
private class PostprocessorContext : IDisposable
|
||||
{
|
||||
private NodeContextImpl _context;
|
||||
@ -211,6 +213,7 @@ namespace nadena.dev.modular_avatar.core.editor.menu
|
||||
|
||||
private Queue<Action> _pendingGeneration = new Queue<Action>();
|
||||
private HashSet<VRCExpressionsMenu> _visitedMenus = new HashSet<VRCExpressionsMenu>();
|
||||
private ImmutableHashSet<object> _visitedNodes = ImmutableHashSet<object>.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the VirtualMenu.
|
||||
@ -348,6 +351,8 @@ namespace nadena.dev.modular_avatar.core.editor.menu
|
||||
_pendingGeneration.Dequeue()();
|
||||
}
|
||||
|
||||
_visitedNodes = rootContext.Visited;
|
||||
|
||||
VirtualMenuNode NodeFor(object key)
|
||||
{
|
||||
if (_resolvedMenu.TryGetValue(key, out var node)) return node;
|
||||
@ -423,5 +428,10 @@ namespace nadena.dev.modular_avatar.core.editor.menu
|
||||
{
|
||||
return _visitedMenus.Contains(menu);
|
||||
}
|
||||
|
||||
public bool ContainsNode(ModularAvatarMenuItem item)
|
||||
{
|
||||
return _visitedNodes.Contains(item);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
namespace nadena.dev.modular_avatar.core
|
||||
{
|
||||
[AddComponentMenu("Modular Avatar/MA Control Group")]
|
||||
public class ControlGroup : ActionController
|
||||
public class ControlGroup : AvatarTagComponent
|
||||
{
|
||||
public bool isSynced = true;
|
||||
public bool isSaved = true;
|
||||
|
Loading…
Reference in New Issue
Block a user