feat: show parameter checkboxes when parameters are defined elsewhere/multiselect is active (#1000)

Closes: #994
This commit is contained in:
bd_ 2024-08-13 20:32:42 -07:00 committed by GitHub
parent 81bcd14bcd
commit 3eea882019
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -8,6 +8,7 @@ using nadena.dev.modular_avatar.core.menu;
using nadena.dev.ndmf; using nadena.dev.ndmf;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using VRC.SDK3.Avatars.Components;
using VRC.SDK3.Avatars.ScriptableObjects; using VRC.SDK3.Avatars.ScriptableObjects;
using static nadena.dev.modular_avatar.core.editor.Localization; using static nadena.dev.modular_avatar.core.editor.Localization;
using Object = UnityEngine.Object; using Object = UnityEngine.Object;
@ -57,7 +58,8 @@ namespace nadena.dev.modular_avatar.core.editor
public bool AlwaysExpandContents = false; public bool AlwaysExpandContents = false;
public bool ExpandContents = false; public bool ExpandContents = false;
private readonly HashSet<string> _knownParameters = new(); private readonly Dictionary<string, ProvidedParameter> _knownParameters = new();
private bool _parameterSourceNotDetermined;
public MenuItemCoreGUI(SerializedObject obj, Action redraw) public MenuItemCoreGUI(SerializedObject obj, Action redraw)
{ {
@ -109,22 +111,37 @@ namespace nadena.dev.modular_avatar.core.editor
private void InitKnownParameters() private void InitKnownParameters()
{ {
if (_parameterReference == null) return; var paramRef = _parameterReference;
if (_parameterReference == null)
// TODO: This could give incorrect results in some cases when we have multiple objects selected with
// different rename contexts.
paramRef = (_obj.targetObjects[0] as Component)?.gameObject;
var rootParameters = ParameterInfo.ForUI.GetParametersForObject( if (paramRef == null)
RuntimeUtil.FindAvatarInParents(_parameterReference.transform).gameObject {
).Select(p => p.EffectiveName).ToHashSet(); _parameterSourceNotDetermined = true;
return;
}
var remaps = ParameterInfo.ForUI.GetParameterRemappingsAt(_parameterReference); Dictionary<string, ProvidedParameter> rootParameters = new();
foreach (var param in ParameterInfo.ForUI.GetParametersForObject(
RuntimeUtil.FindAvatarInParents(paramRef.transform).gameObject
).Where(p => p.Namespace == ParameterNamespace.Animator)
)
rootParameters[param.EffectiveName] = param;
var remaps = ParameterInfo.ForUI.GetParameterRemappingsAt(paramRef);
foreach (var remap in remaps) foreach (var remap in remaps)
{ {
if (remap.Key.Item1 != ParameterNamespace.Animator) continue; if (remap.Key.Item1 != ParameterNamespace.Animator) continue;
if (rootParameters.Contains(remap.Value.ParameterName)) _knownParameters.Add(remap.Key.Item2); if (rootParameters.ContainsKey(remap.Value.ParameterName))
_knownParameters[remap.Key.Item2] = rootParameters[remap.Value.ParameterName];
} }
foreach (var rootParam in rootParameters) foreach (var rootParam in rootParameters)
if (!remaps.ContainsKey((ParameterNamespace.Animator, rootParam))) if (!remaps.ContainsKey((ParameterNamespace.Animator, rootParam.Key)))
_knownParameters.Add(rootParam); _knownParameters[rootParam.Key] = rootParam.Value;
} }
/// <summary> /// <summary>
@ -163,7 +180,12 @@ namespace nadena.dev.modular_avatar.core.editor
_previewGUI = new MenuPreviewGUI(redraw); _previewGUI = new MenuPreviewGUI(redraw);
} }
private void DrawHorizontalToggleProp(SerializedProperty prop, GUIContent label) private void DrawHorizontalToggleProp(
SerializedProperty prop,
GUIContent label,
bool? forceMixedValues = null,
bool? forceValue = null
)
{ {
var toggleSize = EditorStyles.toggle.CalcSize(new GUIContent()); var toggleSize = EditorStyles.toggle.CalcSize(new GUIContent());
var labelSize = EditorStyles.label.CalcSize(label); var labelSize = EditorStyles.label.CalcSize(label);
@ -172,15 +194,22 @@ namespace nadena.dev.modular_avatar.core.editor
var rect = EditorGUILayout.GetControlRect(GUILayout.Width(width)); var rect = EditorGUILayout.GetControlRect(GUILayout.Width(width));
EditorGUI.BeginProperty(rect, label, prop); EditorGUI.BeginProperty(rect, label, prop);
if (forceMixedValues != null) EditorGUI.showMixedValue = forceMixedValues.Value;
if (forceValue != null)
{
EditorGUI.ToggleLeft(rect, label, forceValue.Value);
}
else
{
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
var value = EditorGUI.ToggleLeft(rect, label, prop.boolValue); var value = EditorGUI.ToggleLeft(rect, label, prop.boolValue);
if (EditorGUI.EndChangeCheck()) prop.boolValue = value; if (EditorGUI.EndChangeCheck()) prop.boolValue = value;
}
EditorGUI.EndProperty(); EditorGUI.EndProperty();
} }
private float lastWidth;
public void DoGUI() public void DoGUI()
{ {
EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginHorizontal();
@ -200,16 +229,80 @@ namespace nadena.dev.modular_avatar.core.editor
_parameterGUI.DoGUI(true); _parameterGUI.DoGUI(true);
var paramName = _parameterName.stringValue; var paramName = _parameterName.stringValue;
if (!_parameterName.hasMultipleDifferentValues && !_knownParameters.Contains(paramName))
{
EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginHorizontal();
DrawHorizontalToggleProp(_prop_isDefault, G("menuitem.prop.is_default"));
GUILayout.FlexibleSpace(); bool? forceMixedValues = _parameterName.hasMultipleDifferentValues ? true : null;
DrawHorizontalToggleProp(_prop_isSaved, G("menuitem.prop.is_saved")); var knownParameter = _parameterName.hasMultipleDifferentValues
GUILayout.FlexibleSpace(); ? null
DrawHorizontalToggleProp(_prop_isSynced, G("menuitem.prop.is_synced")); : _knownParameters.GetValueOrDefault(paramName);
EditorGUILayout.EndHorizontal();
var knownParamDefault = knownParameter?.DefaultValue;
var isDefaultByKnownParam =
knownParamDefault != null ? _value.floatValue == knownParamDefault : (bool?)null;
Object controller = knownParameter?.Source;
var controllerIsElsewhere = controller != null && !(controller is ModularAvatarMenuItem);
// If we can't figure out what to reference the parameter names to, disable the UI
controllerIsElsewhere = controllerIsElsewhere || _parameterSourceNotDetermined;
using (new EditorGUI.DisabledScope(
_parameterName.hasMultipleDifferentValues || controllerIsElsewhere)
)
{
// If we have multiple menu items selected, it probably doesn't make sense to make them all default.
// But, we do want to see if _any_ are default.
var anyIsDefault = _prop_isDefault.hasMultipleDifferentValues || _prop_isDefault.boolValue;
var multipleSelections = _obj.targetObjects.Length > 1;
var mixedIsDefault = multipleSelections && anyIsDefault;
using (new EditorGUI.DisabledScope(multipleSelections))
{
DrawHorizontalToggleProp(_prop_isDefault, G("menuitem.prop.is_default"), mixedIsDefault,
multipleSelections ? false : isDefaultByKnownParam);
} }
GUILayout.FlexibleSpace();
var isSavedMixed = forceMixedValues ??
(_parameterName.hasMultipleDifferentValues || controllerIsElsewhere ? true : null);
DrawHorizontalToggleProp(_prop_isSaved, G("menuitem.prop.is_saved"), isSavedMixed);
GUILayout.FlexibleSpace();
DrawHorizontalToggleProp(_prop_isSynced, G("menuitem.prop.is_synced"), forceMixedValues,
knownParameter?.WantSynced);
}
if (controllerIsElsewhere)
{
var refStyle = EditorStyles.toggle;
var refContent = new GUIContent("test");
var refRect = refStyle.CalcSize(refContent);
var height = refRect.y + EditorStyles.toggle.margin.top + EditorStyles.toggle.margin.bottom;
GUILayout.FlexibleSpace();
var style = new GUIStyle(EditorStyles.miniButton);
style.fixedWidth = 0;
style.fixedHeight = 0;
style.stretchHeight = true;
style.stretchWidth = true;
style.imagePosition = ImagePosition.ImageOnly;
var icon = EditorGUIUtility.FindTexture("d_Search Icon");
var rect = GUILayoutUtility.GetRect(new GUIContent(), style, GUILayout.ExpandWidth(false),
GUILayout.Width(height), GUILayout.Height(height));
if (GUI.Button(rect, new GUIContent(), style))
{
if (controller is VRCAvatarDescriptor desc) controller = desc.expressionParameters;
Selection.activeObject = controller;
EditorGUIUtility.PingObject(controller);
}
rect.xMin += 2;
rect.yMin += 2;
rect.xMax -= 2;
rect.yMax -= 2;
GUI.DrawTexture(rect, icon);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical(); EditorGUILayout.EndVertical();