support disabling different parameters based on attached actions

This commit is contained in:
bd_ 2023-02-28 23:50:16 +09:00
parent ed1ae08d04
commit 64d831672a
6 changed files with 143 additions and 75 deletions

View File

@ -1,12 +1,9 @@
using System;
using System.Linq;
using System.Runtime.Serialization;
using Codice.CM.Common.Tree.Partial;
using nadena.dev.modular_avatar.core.menu;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using VRC.SDK3.Avatars.ScriptableObjects;
using static nadena.dev.modular_avatar.core.editor.Localization;
@ -54,11 +51,23 @@ namespace nadena.dev.modular_avatar.core.editor
private bool _hasActions;
private bool HasActions()
private bool HasActions(TargetParameter? p = null)
{
return _toggleGroup != null && _obj.targetObjects.Any(o =>
o is ModularAvatarMenuItem c && c.GetComponent<MenuAction>() != null
);
{
if (!(o is ModularAvatarMenuItem c)) return false;
if (p.HasValue)
{
foreach (var component in c.GetComponents<MenuAction>())
{
if (component.BindsParameter(p.Value)) return true;
}
return false;
}
return true;
});
}
public MenuItemCoreGUI(SerializedObject obj, Action redraw)
@ -162,7 +171,7 @@ namespace nadena.dev.modular_avatar.core.editor
}
}
_parameterGUI.DoGUI(!_hasActions);
_parameterGUI.DoGUI(!_hasActions || !HasActions(TargetParameter.BaseParameter));
EditorGUILayout.EndVertical();
@ -286,7 +295,8 @@ namespace nadena.dev.modular_avatar.core.editor
{
EnsureParameterCount(1);
_subParams[0].DoGUI(true, G("menuitem.param.rotation"));
_subParams[0].DoGUI(!_hasActions || !HasActions(TargetParameter.RadialParam),
G("menuitem.param.rotation"));
break;
}
@ -298,8 +308,10 @@ namespace nadena.dev.modular_avatar.core.editor
EditorGUILayout.LabelField("Parameters", EditorStyles.boldLabel);
EditorGUILayout.Space(2);
_subParams[0].DoGUI(true, G("menuitem.param.horizontal"));
_subParams[1].DoGUI(true, G("menuitem.param.vertical"));
_subParams[0].DoGUI(!_hasActions || !HasActions(TargetParameter.Horizontal),
G("menuitem.param.horizontal"));
_subParams[1].DoGUI(!_hasActions || !HasActions(TargetParameter.Vertical),
G("menuitem.param.vertical"));
DoFourAxisLabels(false);
@ -396,10 +408,10 @@ namespace nadena.dev.modular_avatar.core.editor
center.xMin += blockWidth;
center.xMax -= blockWidth;
SingleLabel(0, up);
SingleLabel(1, right);
SingleLabel(2, down);
SingleLabel(3, left);
SingleLabel(0, up, TargetParameter.Up);
SingleLabel(1, right, TargetParameter.Right);
SingleLabel(2, down, TargetParameter.Down);
SingleLabel(3, left, TargetParameter.Left);
var rect_param_l = center;
rect_param_l.yMin = rect_param_l.yMax - EditorGUIUtility.singleLineHeight;
@ -409,7 +421,7 @@ namespace nadena.dev.modular_avatar.core.editor
if (showParams) CenterLabel(rect_param_l, G("menuitem.prop.parameter"), EditorStyles.label);
CenterLabel(rect_name_l, G("menuitem.prop.label"), EditorStyles.label);
void SingleLabel(int index, Rect block)
void SingleLabel(int index, Rect block, TargetParameter parameter)
{
var prop_name = _labels[index].FindPropertyRelative(nameof(VRCExpressionsMenu.Control.Label.name));
var prop_icon = _labels[index].FindPropertyRelative(nameof(VRCExpressionsMenu.Control.Label.icon));
@ -426,7 +438,7 @@ namespace nadena.dev.modular_avatar.core.editor
EditorGUI.PropertyField(rect_name, prop_name, GUIContent.none);
if (showParams)
{
_subParams[index].DoGUI(rect_param, true, GUIContent.none);
_subParams[index].DoGUI(rect_param, !_hasActions || !HasActions(parameter), GUIContent.none);
}
var tex = prop_icon.objectReferenceValue as Texture;

View File

@ -23,7 +23,7 @@ namespace nadena.dev.modular_avatar.core.editor
_redraw = redraw;
}
public void DoGUI(bool enabled = true, GUIContent label = null)
public void DoGUI(bool enabled, GUIContent label = null)
{
DoGUI(EditorGUILayout.GetControlRect(
true,
@ -31,7 +31,7 @@ namespace nadena.dev.modular_avatar.core.editor
), enabled, label);
}
public void DoGUI(Rect rect, bool enabled = true, GUIContent label = null)
public void DoGUI(Rect rect, bool enabled, GUIContent label = null)
{
label = label ?? G("menuitem.prop.parameter");

View File

@ -315,11 +315,11 @@ namespace nadena.dev.modular_avatar.core.editor
void MergeCurves(
IDictionary<MenuCurveBinding, (Component, AnimationCurve)> curves,
ModularAvatarMenuItem item,
Func<MenuAction, IDictionary<MenuCurveBinding, AnimationCurve>> getCurves,
Func<SwitchedMenuAction, IDictionary<MenuCurveBinding, AnimationCurve>> getCurves,
bool ignoreDuplicates
)
{
foreach (var action in item.GetComponents<MenuAction>())
foreach (var action in item.GetComponents<SwitchedMenuAction>())
{
var newCurves = getCurves(action);

View File

@ -7,62 +7,8 @@ using Object = System.Object;
namespace nadena.dev.modular_avatar.core
{
public sealed class MenuCurveBinding
{
public readonly GameObject target;
public readonly Type type;
public readonly string property;
public MenuCurveBinding(GameObject target, Type type, string property)
{
this.target = target;
this.type = type;
this.property = property;
}
private bool Equals(MenuCurveBinding other)
{
return target == other.target && type == other.type && property == other.property;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((MenuCurveBinding) obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (target != null ? target.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (type != null ? type.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (property != null ? property.GetHashCode() : 0);
return hashCode;
}
}
}
public interface MenuAction
{
/// <summary>
/// Returns the curves applied when this action is active
/// </summary>
/// <returns></returns>
ImmutableDictionary<MenuCurveBinding, AnimationCurve> GetCurves();
/// <summary>
/// Returns the curves applied when this action is inactive (and no other actions override).
/// </summary>
/// <param name="isDefault">True if this action is part of the default toggle option.</param>
/// <returns></returns>
ImmutableDictionary<MenuCurveBinding, AnimationCurve> GetInactiveCurves(bool isDefault);
}
[RequireComponent(typeof(ModularAvatarMenuItem))]
public class ActionToggleObject : AvatarTagComponent, MenuAction
public class ActionToggleObject : AvatarTagComponent, SwitchedMenuAction
{
[Serializable]
public class ObjectEntry
@ -102,5 +48,10 @@ namespace nadena.dev.modular_avatar.core
}
).ToImmutableDictionary();
}
public bool BindsParameter(TargetParameter parameter)
{
return parameter == TargetParameter.BaseParameter;
}
}
}

View File

@ -0,0 +1,102 @@
using System;
using System.Collections.Immutable;
using UnityEngine;
namespace nadena.dev.modular_avatar.core
{
public interface MenuAction
{
/// <summary>
/// Returns whether this action binds to the given parameter.
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
bool BindsParameter(TargetParameter parameter);
}
public interface SwitchedMenuAction : MenuAction
{
/// <summary>
/// Returns the curves applied when this action is active
/// </summary>
/// <returns></returns>
ImmutableDictionary<MenuCurveBinding, AnimationCurve> GetCurves();
/// <summary>
/// Returns the curves applied when this action is inactive (and no other actions override).
/// </summary>
/// <param name="isDefault">True if this action is part of the default toggle option.</param>
/// <returns></returns>
ImmutableDictionary<MenuCurveBinding, AnimationCurve> GetInactiveCurves(bool isDefault);
}
public enum TargetParameter
{
BaseParameter,
RadialParam,
Horizontal,
Vertical,
Up,
Right,
Down,
Left
}
public static class TargetParameterExtension
{
public static int Index(this TargetParameter p)
{
switch (p)
{
case TargetParameter.BaseParameter:
return -1;
case TargetParameter.RadialParam: return 0;
case TargetParameter.Horizontal: return 0;
case TargetParameter.Vertical: return 1;
case TargetParameter.Up: return 0;
case TargetParameter.Right: return 1;
case TargetParameter.Down: return 2;
case TargetParameter.Left: return 3;
default: throw new NotImplementedException();
}
}
}
public sealed class MenuCurveBinding
{
public readonly GameObject target;
public readonly Type type;
public readonly string property;
public MenuCurveBinding(GameObject target, Type type, string property)
{
this.target = target;
this.type = type;
this.property = property;
}
private bool Equals(MenuCurveBinding other)
{
return target == other.target && type == other.type && property == other.property;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((MenuCurveBinding) obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (target != null ? target.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (type != null ? type.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (property != null ? property.GetHashCode() : 0);
return hashCode;
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 33005b045768474d8ae6f789aa03361b
timeCreated: 1677595006