diff --git a/Editor/Inspector/AvatarParametersEditor.cs.meta b/Editor/Inspector/AvatarParametersEditor.cs.meta deleted file mode 100644 index aa9165bc..00000000 --- a/Editor/Inspector/AvatarParametersEditor.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 21089a5ec87c4e4fa1616376cbb8fbd7 -timeCreated: 1664847495 \ No newline at end of file diff --git a/Editor/Inspector/Common/UXMLExtensions.cs b/Editor/Inspector/Common/UXMLExtensions.cs index c9d968b1..582ca69a 100644 --- a/Editor/Inspector/Common/UXMLExtensions.cs +++ b/Editor/Inspector/Common/UXMLExtensions.cs @@ -12,6 +12,7 @@ namespace nadena.dev.modular_avatar.core.editor private static Dictionary> _localizers = new Dictionary>(); + [Obsolete("Use UIElementLocalizer instead")] public static VisualElement Localize(this VisualTreeAsset asset) { var root = asset.CloneTree(); diff --git a/Editor/Inspector/Parameters.meta b/Editor/Inspector/Parameters.meta new file mode 100644 index 00000000..76502279 --- /dev/null +++ b/Editor/Inspector/Parameters.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5b0bd0302666483e9fb9572cc5df36e1 +timeCreated: 1706005296 \ No newline at end of file diff --git a/Editor/Inspector/Parameters/AvatarParametersEditor.cs b/Editor/Inspector/Parameters/AvatarParametersEditor.cs new file mode 100644 index 00000000..adcda6ed --- /dev/null +++ b/Editor/Inspector/Parameters/AvatarParametersEditor.cs @@ -0,0 +1,186 @@ +#if MA_VRCSDK3_AVATARS && UNITY_2022_1_OR_NEWER + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using nadena.dev.modular_avatar.core.editor.Parameters; +using NUnit.Framework; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEditorInternal; +using UnityEngine; +using UnityEngine.UIElements; +using static nadena.dev.modular_avatar.core.editor.Localization; +using Debug = System.Diagnostics.Debug; + +namespace nadena.dev.modular_avatar.core.editor +{ + [CustomEditor(typeof(ModularAvatarParameters))] + internal class AvatarParametersEditor : MAEditorBase + { + [SerializeField] private StyleSheet uss; + [SerializeField] private VisualTreeAsset uxml; + + private ListView listView, unregisteredListView; + + private List detectedParameters = new List(); + + protected override void OnInnerInspectorGUI() + { + throw new System.NotImplementedException(); + } + + protected override VisualElement CreateInnerInspectorGUI() + { + var root = uxml.CloneTree(); + UI.Localize(root); + root.styleSheets.Add(uss); + /* + var listView = new ListView(); + + listView.BindProperty(serializedObject.FindProperty(nameof(ModularAvatarParameters.parameters))); + listView.itemHeight = 20; + listView.style.flexGrow = 1.0f; + listView.selectionType = SelectionType.Single; + listView.makeItem = () => new TextElement(); + listView.bindItem = (elem, i) => ((TextElement) elem).text = $"Item {i}"; + + root.Q("ListViewContainer").Add(listView); + */ + listView = root.Q("Parameters"); + /*listView.makeItem = () => new TextElement(); + listView.bindItem = (elem, i) => ((TextElement) elem).text = $"Item {i}"; + */ + listView.itemHeight = 100; + #if UNITY_2022_1_OR_NEWER + listView.showBoundCollectionSize = false; + listView.virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight; + #endif + + unregisteredListView = root.Q("UnregisteredParameters"); + + unregisteredListView.showBoundCollectionSize = false; + unregisteredListView.virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight; + + unregisteredListView.makeItem = () => + { + var row = new VisualElement(); + row.AddToClassList("DetectedParameter"); + + return row; + }; + unregisteredListView.bindItem = (elem, i) => + { + var parameter = detectedParameters[i]; + elem.Clear(); + + var button = new Button(); + button.text = "merge_parameter.ui.add_button"; + button.AddToClassList("ndmf-tr"); + UI.Localize(button); + + var label = new Label(); + label.text = parameter.OriginalName; + elem.Add(button); + elem.Add(label); + + if (parameter.Source != null) + { + var tex = EditorGUIUtility.FindTexture("d_Search Icon"); + + var sourceButton = new Button(); + sourceButton.AddToClassList("SourceButton"); + sourceButton.text = ""; + + var image = new Image(); + sourceButton.Add(image); + image.image = tex; + + sourceButton.clicked += () => + { + EditorGUIUtility.PingObject(parameter.Source); + }; + elem.Add(sourceButton); + } + + button.clicked += () => + { + detectedParameters.RemoveAt(i); + + var target = (ModularAvatarParameters)this.target; + target.parameters.Add(new ParameterConfig() + { + internalParameter = false, + nameOrPrefix = parameter.OriginalName, + isPrefix = parameter.IsPrefix, + remapTo = "", + syncType = parameter.syncType, + defaultValue = parameter.defaultValue, + saved = parameter.saved, + }); + EditorUtility.SetDirty(target); + PrefabUtility.RecordPrefabInstancePropertyModifications(target); + + unregisteredListView.RefreshItems(); + listView.RefreshItems(); + listView.selectedIndex = target.parameters.Count - 1; + }; + }; + + unregisteredListView.itemsSource = detectedParameters; + + var unregisteredFoldout = root.Q("UnregisteredFoldout"); + unregisteredFoldout.RegisterValueChangedCallback(evt => + { + if (evt.newValue) + { + DetectParameters(); + } + }); + + root.Bind(serializedObject); + + listView.itemsRemoved += _ => + { + if (unregisteredFoldout.value) + { + // We haven't committed the removal to the backing object yet, so defer this one frame to allow that to + // happen. + EditorApplication.delayCall += DetectParameters; + } + }; + + return root; + } + + private void DetectParameters() + { + var known = new HashSet(); + var knownPB = new HashSet(); + + var target = (ModularAvatarParameters)this.target; + foreach (var parameter in target.parameters) + { + if (parameter.isPrefix) + { + knownPB.Add(parameter.nameOrPrefix); + } + else + { + known.Add(parameter.nameOrPrefix); + } + } + + var detected = ParameterPolicy.ProbeParameters(target.gameObject); + detectedParameters.Clear(); + detectedParameters.AddRange( + detected.Values + .Where(p => p.IsPrefix ? !knownPB.Contains(p.OriginalName) : !known.Contains(p.OriginalName)) + .OrderBy(p => p.OriginalName) + ); + unregisteredListView.RefreshItems(); + } + } +} +#endif \ No newline at end of file diff --git a/Editor/Inspector/Parameters/AvatarParametersEditor.cs.meta b/Editor/Inspector/Parameters/AvatarParametersEditor.cs.meta new file mode 100644 index 00000000..221d0e89 --- /dev/null +++ b/Editor/Inspector/Parameters/AvatarParametersEditor.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 21089a5ec87c4e4fa1616376cbb8fbd7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - uss: {fileID: 7433441132597879392, guid: d72e507abb5be28499d149b3c22f80bc, type: 3} + - uxml: {fileID: 9197481963319205126, guid: 00e4e2766c4ae9f4687e98ed34685b4f, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspector/AvatarParametersEditor.cs b/Editor/Inspector/Parameters/AvatarParametersEditor2019.cs similarity index 97% rename from Editor/Inspector/AvatarParametersEditor.cs rename to Editor/Inspector/Parameters/AvatarParametersEditor2019.cs index ff330cc1..ff0c4340 100644 --- a/Editor/Inspector/AvatarParametersEditor.cs +++ b/Editor/Inspector/Parameters/AvatarParametersEditor2019.cs @@ -1,6 +1,5 @@ #if MA_VRCSDK3_AVATARS -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -12,22 +11,10 @@ using Debug = System.Diagnostics.Debug; namespace nadena.dev.modular_avatar.core.editor { - [CustomPropertyDrawer(typeof(ParameterSyncType))] - internal class ParameterSyncTypeDrawer : EnumDrawer - { - protected override string localizationPrefix => "params.syncmode"; - - protected override Array enumValues => new object[] - { - ParameterSyncType.NotSynced, - ParameterSyncType.Bool, - ParameterSyncType.Float, - ParameterSyncType.Int, - }; - } - +#if !UNITY_2022_1_OR_NEWER [CustomEditor(typeof(ModularAvatarParameters))] - internal class AvatarParametersEditor : MAEditorBase +#endif + internal class AvatarParametersEditor2019 : MAEditorBase { /********************************************************************** * | Field name | Remap to / config | diff --git a/Editor/Inspector/Parameters/AvatarParametersEditor2019.cs.meta b/Editor/Inspector/Parameters/AvatarParametersEditor2019.cs.meta new file mode 100644 index 00000000..015ce842 --- /dev/null +++ b/Editor/Inspector/Parameters/AvatarParametersEditor2019.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7fd14c3a2e157c4dba0955d7d64cf5c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspector/Parameters/ParameterConfigDrawer.cs b/Editor/Inspector/Parameters/ParameterConfigDrawer.cs new file mode 100644 index 00000000..5c11f639 --- /dev/null +++ b/Editor/Inspector/Parameters/ParameterConfigDrawer.cs @@ -0,0 +1,83 @@ +#if MA_VRCSDK3_AVATARS && UNITY_2022_1_OR_NEWER + +using System; +using nadena.dev.ndmf.localization; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace nadena.dev.modular_avatar.core.editor.Parameters +{ + [CustomPropertyDrawer(typeof(ParameterConfig))] + internal class ParameterConfigDrawer : PropertyDrawer + { + [SerializeField] private StyleSheet uss; + [SerializeField] private VisualTreeAsset uxml; + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var rootPath = "Packages/nadena.dev.modular-avatar/Editor/Inspector/Parameters"; + var uss = AssetDatabase.LoadAssetAtPath(rootPath + "/Parameters.uss"); + var uxml = AssetDatabase.LoadAssetAtPath(rootPath + "/ParameterConfigDrawer.uxml"); + + var root = uxml.CloneTree(); + Localization.UI.Localize(root); + root.styleSheets.Add(uss); + + var foldout = root.Q(); + var foldoutLabel = foldout?.Q