mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-01-17 11:50:11 +08:00
ui: improve handling of saved/synced checkboxes on MenuItems with sibling items (#1095)
We will now force the state of all related MenuItems to match when the synced/saved checkboxes are updated on the Menu Item UI.
This commit is contained in:
parent
e07b18d87e
commit
d403f1b178
@ -202,16 +202,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
if (forceMixedValues != null) EditorGUI.showMixedValue = forceMixedValues.Value;
|
if (forceMixedValues != null) EditorGUI.showMixedValue = forceMixedValues.Value;
|
||||||
|
|
||||||
if (forceValue != null)
|
EditorGUI.BeginChangeCheck();
|
||||||
{
|
var value = EditorGUI.ToggleLeft(rect, label, forceValue ?? prop.boolValue);
|
||||||
EditorGUI.ToggleLeft(rect, label, forceValue.Value);
|
if (EditorGUI.EndChangeCheck()) prop.boolValue = value;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EditorGUI.BeginChangeCheck();
|
|
||||||
var value = EditorGUI.ToggleLeft(rect, label, prop.boolValue);
|
|
||||||
if (EditorGUI.EndChangeCheck()) prop.boolValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorGUI.EndProperty();
|
EditorGUI.EndProperty();
|
||||||
}
|
}
|
||||||
@ -438,26 +431,42 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
// For now, don't show the UI in this case.
|
// For now, don't show the UI in this case.
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var multipleSelections = _obj.targetObjects.Length > 1;
|
||||||
|
|
||||||
var paramName = _parameterName.stringValue;
|
var paramName = _parameterName.stringValue;
|
||||||
|
var siblings = FindSiblingMenuItems(_obj);
|
||||||
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
bool? forceMixedValues = _parameterName.hasMultipleDifferentValues ? true : null;
|
var forceMixedValues = _parameterName.hasMultipleDifferentValues;
|
||||||
|
|
||||||
|
var syncedIsMixed = forceMixedValues || _prop_isSynced.hasMultipleDifferentValues ||
|
||||||
|
siblings.Any(s => s.isSynced != _prop_isSynced.boolValue);
|
||||||
|
var savedIsMixed = forceMixedValues || _prop_isSaved.hasMultipleDifferentValues ||
|
||||||
|
siblings.Any(s => s.isSaved != _prop_isSaved.boolValue);
|
||||||
|
|
||||||
var knownParameter = _parameterName.hasMultipleDifferentValues
|
var knownParameter = _parameterName.hasMultipleDifferentValues
|
||||||
? null
|
? null
|
||||||
: _knownParameters.GetValueOrDefault(paramName);
|
: _knownParameters.GetValueOrDefault(paramName);
|
||||||
|
|
||||||
|
var knownSource = knownParameter?.Source;
|
||||||
|
var externalSource = knownSource != null && knownSource is not ModularAvatarMenuItem;
|
||||||
|
|
||||||
|
if (externalSource) savedIsMixed = true; // NDMF doesn't yet support querying for the saved state
|
||||||
|
var forceSyncedValue = externalSource ? knownParameter?.WantSynced : null;
|
||||||
|
|
||||||
var knownParamDefault = knownParameter?.DefaultValue;
|
var knownParamDefault = knownParameter?.DefaultValue;
|
||||||
var isDefaultByKnownParam =
|
var isDefaultByKnownParam =
|
||||||
knownParamDefault != null ? _value.floatValue == knownParamDefault : (bool?)null;
|
knownParamDefault != null ? _value.floatValue == knownParamDefault : (bool?)null;
|
||||||
|
|
||||||
if (knownParameter != null && knownParameter.Source is ModularAvatarMenuItem otherMenuItem)
|
if (knownParameter != null && knownParameter.Source is ModularAvatarMenuItem)
|
||||||
isDefaultByKnownParam = null;
|
isDefaultByKnownParam = null;
|
||||||
|
|
||||||
Object controller = knownParameter?.Source;
|
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
|
// If we can't figure out what to reference the parameter names to, or if they're controlled by something
|
||||||
controllerIsElsewhere = controllerIsElsewhere || _parameterSourceNotDetermined;
|
// other than the Menu Item component itself, disable the UI
|
||||||
|
var controllerIsElsewhere = externalSource || _parameterSourceNotDetermined;
|
||||||
|
|
||||||
using (new EditorGUI.DisabledScope(
|
using (new EditorGUI.DisabledScope(
|
||||||
_parameterName.hasMultipleDifferentValues || controllerIsElsewhere)
|
_parameterName.hasMultipleDifferentValues || controllerIsElsewhere)
|
||||||
@ -466,28 +475,42 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
// If we have multiple menu items selected, it probably doesn't make sense to make them all default.
|
// 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.
|
// But, we do want to see if _any_ are default.
|
||||||
var anyIsDefault = _prop_isDefault.hasMultipleDifferentValues || _prop_isDefault.boolValue;
|
var anyIsDefault = _prop_isDefault.hasMultipleDifferentValues || _prop_isDefault.boolValue;
|
||||||
var multipleSelections = _obj.targetObjects.Length > 1;
|
|
||||||
var mixedIsDefault = multipleSelections && anyIsDefault;
|
var mixedIsDefault = multipleSelections && anyIsDefault;
|
||||||
using (new EditorGUI.DisabledScope(multipleSelections || isDefaultByKnownParam != null))
|
using (new EditorGUI.DisabledScope(multipleSelections || isDefaultByKnownParam != null))
|
||||||
{
|
{
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
DrawHorizontalToggleProp(_prop_isDefault, G("menuitem.prop.is_default"), mixedIsDefault,
|
DrawHorizontalToggleProp(_prop_isDefault, G("menuitem.prop.is_default"), mixedIsDefault,
|
||||||
multipleSelections ? false : isDefaultByKnownParam);
|
isDefaultByKnownParam);
|
||||||
if (EditorGUI.EndChangeCheck())
|
if (EditorGUI.EndChangeCheck())
|
||||||
{
|
{
|
||||||
_obj.ApplyModifiedProperties();
|
_obj.ApplyModifiedProperties();
|
||||||
ClearConflictingDefaults(_obj);
|
ClearConflictingDefaults(siblings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.FlexibleSpace();
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
var isSavedMixed = forceMixedValues ??
|
EditorGUI.BeginChangeCheck();
|
||||||
(_parameterName.hasMultipleDifferentValues || controllerIsElsewhere ? true : null);
|
DrawHorizontalToggleProp(_prop_isSaved, G("menuitem.prop.is_saved"), savedIsMixed);
|
||||||
DrawHorizontalToggleProp(_prop_isSaved, G("menuitem.prop.is_saved"), isSavedMixed);
|
if (EditorGUI.EndChangeCheck() && siblings != null)
|
||||||
|
foreach (var sibling in siblings)
|
||||||
|
{
|
||||||
|
sibling.isSaved = _prop_isSaved.boolValue;
|
||||||
|
EditorUtility.SetDirty(sibling);
|
||||||
|
PrefabUtility.RecordPrefabInstancePropertyModifications(sibling);
|
||||||
|
}
|
||||||
|
|
||||||
GUILayout.FlexibleSpace();
|
GUILayout.FlexibleSpace();
|
||||||
DrawHorizontalToggleProp(_prop_isSynced, G("menuitem.prop.is_synced"), forceMixedValues,
|
EditorGUI.BeginChangeCheck();
|
||||||
knownParameter?.WantSynced);
|
DrawHorizontalToggleProp(_prop_isSynced, G("menuitem.prop.is_synced"), syncedIsMixed,
|
||||||
|
forceSyncedValue);
|
||||||
|
if (EditorGUI.EndChangeCheck() && siblings != null)
|
||||||
|
foreach (var sibling in siblings)
|
||||||
|
{
|
||||||
|
sibling.isSynced = _prop_isSynced.boolValue;
|
||||||
|
EditorUtility.SetDirty(sibling);
|
||||||
|
PrefabUtility.RecordPrefabInstancePropertyModifications(sibling);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controllerIsElsewhere)
|
if (controllerIsElsewhere)
|
||||||
@ -526,21 +549,22 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearConflictingDefaults(SerializedObject serializedObject)
|
private List<ModularAvatarMenuItem> FindSiblingMenuItems(SerializedObject serializedObject)
|
||||||
{
|
{
|
||||||
if (serializedObject.isEditingMultipleObjects) return;
|
if (serializedObject == null || serializedObject.isEditingMultipleObjects) return null;
|
||||||
|
|
||||||
var myMenuItem = serializedObject.targetObject as ModularAvatarMenuItem;
|
var myMenuItem = serializedObject.targetObject as ModularAvatarMenuItem;
|
||||||
if (myMenuItem == null) return;
|
if (myMenuItem == null) return null;
|
||||||
|
|
||||||
var myParameterName = myMenuItem.Control.parameter.name;
|
var myParameterName = myMenuItem.Control.parameter.name;
|
||||||
if (string.IsNullOrEmpty(myParameterName)) return;
|
if (string.IsNullOrEmpty(myParameterName)) return new List<ModularAvatarMenuItem>();
|
||||||
|
|
||||||
var myMappings = ParameterInfo.ForUI.GetParameterRemappingsAt(myMenuItem.gameObject);
|
var myMappings = ParameterInfo.ForUI.GetParameterRemappingsAt(myMenuItem.gameObject);
|
||||||
if (myMappings.TryGetValue((ParameterNamespace.Animator, myParameterName), out var myReplacement))
|
if (myMappings.TryGetValue((ParameterNamespace.Animator, myParameterName), out var myReplacement))
|
||||||
myParameterName = myReplacement.ParameterName;
|
myParameterName = myReplacement.ParameterName;
|
||||||
|
|
||||||
var avatarRoot = RuntimeUtil.FindAvatarInParents(myMenuItem.gameObject.transform);
|
var avatarRoot = RuntimeUtil.FindAvatarInParents(myMenuItem.gameObject.transform);
|
||||||
|
var siblings = new List<ModularAvatarMenuItem>();
|
||||||
|
|
||||||
foreach (var otherMenuItem in avatarRoot.GetComponentsInChildren<ModularAvatarMenuItem>(true))
|
foreach (var otherMenuItem in avatarRoot.GetComponentsInChildren<ModularAvatarMenuItem>(true))
|
||||||
{
|
{
|
||||||
@ -550,10 +574,25 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
if (string.IsNullOrEmpty(otherParameterName)) continue;
|
if (string.IsNullOrEmpty(otherParameterName)) continue;
|
||||||
|
|
||||||
var otherMappings = ParameterInfo.ForUI.GetParameterRemappingsAt(otherMenuItem.gameObject);
|
var otherMappings = ParameterInfo.ForUI.GetParameterRemappingsAt(otherMenuItem.gameObject);
|
||||||
if (otherMappings.TryGetValue((ParameterNamespace.Animator, otherParameterName), out var otherReplacement))
|
if (otherMappings.TryGetValue((ParameterNamespace.Animator, otherParameterName),
|
||||||
|
out var otherReplacement))
|
||||||
otherParameterName = otherReplacement.ParameterName;
|
otherParameterName = otherReplacement.ParameterName;
|
||||||
|
|
||||||
if (otherParameterName != myParameterName) continue;
|
if (otherParameterName != myParameterName) continue;
|
||||||
|
|
||||||
|
siblings.Add(otherMenuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return siblings;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearConflictingDefaults(List<ModularAvatarMenuItem> siblingItems)
|
||||||
|
{
|
||||||
|
var siblings = siblingItems;
|
||||||
|
if (siblings == null) return;
|
||||||
|
|
||||||
|
foreach (var otherMenuItem in siblings)
|
||||||
|
{
|
||||||
if (otherMenuItem.isDefault)
|
if (otherMenuItem.isDefault)
|
||||||
{
|
{
|
||||||
Undo.RecordObject(otherMenuItem, "");
|
Undo.RecordObject(otherMenuItem, "");
|
||||||
|
Loading…
Reference in New Issue
Block a user