mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2024-12-29 18:55:06 +08:00
ui(parameters): Rebuild MAParameters UI for Unity 2022
This commit is contained in:
parent
07d61b25b2
commit
7df80797d6
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 21089a5ec87c4e4fa1616376cbb8fbd7
|
|
||||||
timeCreated: 1664847495
|
|
@ -12,6 +12,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
private static Dictionary<Type, Action<VisualElement>> _localizers =
|
private static Dictionary<Type, Action<VisualElement>> _localizers =
|
||||||
new Dictionary<Type, Action<VisualElement>>();
|
new Dictionary<Type, Action<VisualElement>>();
|
||||||
|
|
||||||
|
[Obsolete("Use UIElementLocalizer instead")]
|
||||||
public static VisualElement Localize(this VisualTreeAsset asset)
|
public static VisualElement Localize(this VisualTreeAsset asset)
|
||||||
{
|
{
|
||||||
var root = asset.CloneTree();
|
var root = asset.CloneTree();
|
||||||
|
3
Editor/Inspector/Parameters.meta
Normal file
3
Editor/Inspector/Parameters.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5b0bd0302666483e9fb9572cc5df36e1
|
||||||
|
timeCreated: 1706005296
|
186
Editor/Inspector/Parameters/AvatarParametersEditor.cs
Normal file
186
Editor/Inspector/Parameters/AvatarParametersEditor.cs
Normal file
@ -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<DetectedParameter> detectedParameters = new List<DetectedParameter>();
|
||||||
|
|
||||||
|
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<VisualElement>("ListViewContainer").Add(listView);
|
||||||
|
*/
|
||||||
|
listView = root.Q<ListView>("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<ListView>("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<Foldout>("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<string>();
|
||||||
|
var knownPB = new HashSet<string>();
|
||||||
|
|
||||||
|
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
|
13
Editor/Inspector/Parameters/AvatarParametersEditor.cs.meta
Normal file
13
Editor/Inspector/Parameters/AvatarParametersEditor.cs.meta
Normal file
@ -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:
|
@ -1,6 +1,5 @@
|
|||||||
#if MA_VRCSDK3_AVATARS
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -12,22 +11,10 @@ using Debug = System.Diagnostics.Debug;
|
|||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core.editor
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
{
|
{
|
||||||
[CustomPropertyDrawer(typeof(ParameterSyncType))]
|
#if !UNITY_2022_1_OR_NEWER
|
||||||
internal class ParameterSyncTypeDrawer : EnumDrawer<ParameterSyncType>
|
|
||||||
{
|
|
||||||
protected override string localizationPrefix => "params.syncmode";
|
|
||||||
|
|
||||||
protected override Array enumValues => new object[]
|
|
||||||
{
|
|
||||||
ParameterSyncType.NotSynced,
|
|
||||||
ParameterSyncType.Bool,
|
|
||||||
ParameterSyncType.Float,
|
|
||||||
ParameterSyncType.Int,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[CustomEditor(typeof(ModularAvatarParameters))]
|
[CustomEditor(typeof(ModularAvatarParameters))]
|
||||||
internal class AvatarParametersEditor : MAEditorBase
|
#endif
|
||||||
|
internal class AvatarParametersEditor2019 : MAEditorBase
|
||||||
{
|
{
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* | Field name | Remap to / config |
|
* | Field name | Remap to / config |
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d7fd14c3a2e157c4dba0955d7d64cf5c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
83
Editor/Inspector/Parameters/ParameterConfigDrawer.cs
Normal file
83
Editor/Inspector/Parameters/ParameterConfigDrawer.cs
Normal file
@ -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<StyleSheet>(rootPath + "/Parameters.uss");
|
||||||
|
var uxml = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(rootPath + "/ParameterConfigDrawer.uxml");
|
||||||
|
|
||||||
|
var root = uxml.CloneTree();
|
||||||
|
Localization.UI.Localize(root);
|
||||||
|
root.styleSheets.Add(uss);
|
||||||
|
|
||||||
|
var foldout = root.Q<Foldout>();
|
||||||
|
var foldoutLabel = foldout?.Q<Label>();
|
||||||
|
if (foldoutLabel != null)
|
||||||
|
{
|
||||||
|
foldoutLabel.bindingPath = "nameOrPrefix";
|
||||||
|
}
|
||||||
|
|
||||||
|
var miniDisplay = root.Q<VisualElement>("MiniDisplay");
|
||||||
|
miniDisplay.RemoveFromHierarchy();
|
||||||
|
foldoutLabel.parent.Add(miniDisplay);
|
||||||
|
miniDisplay.styleSheets.Add(uss);
|
||||||
|
|
||||||
|
var isPrefixProp = root.Q<PropertyField>("isPrefix");
|
||||||
|
bool isPrefix = false;
|
||||||
|
Action evaluateMiniDisplay = () =>
|
||||||
|
{
|
||||||
|
miniDisplay.style.display = (isPrefix || foldout.value) ? DisplayStyle.None : DisplayStyle.Flex;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
foldout.RegisterValueChangedCallback(evt => evaluateMiniDisplay());
|
||||||
|
|
||||||
|
isPrefixProp.RegisterValueChangeCallback(evt =>
|
||||||
|
{
|
||||||
|
var value = evt.changedProperty.boolValue;
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
root.AddToClassList("ParameterConfig__isPrefix");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
root.RemoveFromClassList("ParameterConfig__isPrefix");
|
||||||
|
}
|
||||||
|
|
||||||
|
isPrefix = value;
|
||||||
|
evaluateMiniDisplay();
|
||||||
|
});
|
||||||
|
|
||||||
|
var remapTo = root.Q<PropertyField>("remapTo");
|
||||||
|
var remapToPlaceholder = root.Q<TextField>("remapToPlaceholder");
|
||||||
|
remapToPlaceholder.SetEnabled(false);
|
||||||
|
|
||||||
|
remapToPlaceholder.labelElement.AddToClassList("ndmf-tr");
|
||||||
|
|
||||||
|
root.Q<PropertyField>("internalParameter").RegisterValueChangeCallback(evt =>
|
||||||
|
{
|
||||||
|
remapTo.style.display = evt.changedProperty.boolValue ? DisplayStyle.None : DisplayStyle.Flex;
|
||||||
|
remapToPlaceholder.style.display = evt.changedProperty.boolValue ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
|
});
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 633daf89a52e492a9b55aa31e60ec080
|
||||||
|
timeCreated: 1706005304
|
28
Editor/Inspector/Parameters/ParameterConfigDrawer.uxml
Normal file
28
Editor/Inspector/Parameters/ParameterConfigDrawer.uxml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:engine="UnityEditor.UIElements" editor="UnityEditor.UIElements" ma="nadena.dev.modular_avatar.core.editor" editor-extension-mode="False">
|
||||||
|
<ui:VisualElement name="MiniDisplay">
|
||||||
|
<ui:Label text="merge_parameter.ui.defaultValue" class="ndmf-tr"/>
|
||||||
|
<ui:FloatField binding-path="defaultValue"/>
|
||||||
|
<ui:Label text="merge_parameter.ui.saved" class="ndmf-tr"/>
|
||||||
|
<ui:Toggle binding-path="saved"/>
|
||||||
|
</ui:VisualElement>
|
||||||
|
|
||||||
|
<ui:Foldout name="ParameterConfigRoot" text="(placeholder)" value="false">
|
||||||
|
<engine:PropertyField binding-path="nameOrPrefix" label="merge_parameter.ui.name" name="f-name" class="ndmf-tr ParameterConfig__isPrefix_falseOnly" />
|
||||||
|
<engine:PropertyField binding-path="nameOrPrefix" label="merge_parameter.ui.prefix" name="f-prefix" class="ndmf-tr ParameterConfig__isPrefix_trueOnly" />
|
||||||
|
<engine:PropertyField binding-path="remapTo" label="merge_parameter.ui.remapTo" name="remapTo" class="ndmf-tr" />
|
||||||
|
<ui:TextField label="##merge_parameter.ui.remapTo" text="merge_parameter.ui.remapTo.automatic" name="remapToPlaceholder" enabled="false" class="ndmf-tr unity-base-field__aligned" />
|
||||||
|
|
||||||
|
<engine:PropertyField binding-path="defaultValue" name="defaultValue" label="merge_parameter.ui.defaultValue" class="ndmf-tr ParameterConfig__isPrefix_falseOnly"/>
|
||||||
|
|
||||||
|
<engine:PropertyField binding-path="saved" label="merge_parameter.ui.saved" class="ndmf-tr ParameterConfig__isPrefix_falseOnly" />
|
||||||
|
|
||||||
|
<ui:Foldout text="merge_parameter.ui.details" class="ndmf-tr" value="false">
|
||||||
|
<engine:PropertyField binding-path="internalParameter" label="merge_parameter.ui.internalParameter" name="internalParameter" class="ndmf-tr" />
|
||||||
|
<engine:PropertyField binding-path="isPrefix" label="merge_parameter.ui.isPrefix" name="isPrefix" class="ndmf-tr" />
|
||||||
|
<engine:PropertyField binding-path="syncType" label="merge_parameter.ui.syncType" class="ParameterConfig__isPrefix_falseOnly ndmf-tr" />
|
||||||
|
<engine:PropertyField binding-path="localOnly" label="merge_parameter.ui.localOnly" class="ParameterConfig__isPrefix_falseOnly ndmf-tr" />
|
||||||
|
</ui:Foldout>
|
||||||
|
|
||||||
|
</ui:Foldout>
|
||||||
|
|
||||||
|
</ui:UXML>
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bdea2a4cbb794433bdc6dd734e19d29c
|
||||||
|
timeCreated: 1706008148
|
21
Editor/Inspector/Parameters/ParameterSyncTypeDrawer.cs
Normal file
21
Editor/Inspector/Parameters/ParameterSyncTypeDrawer.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using System;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
|
{
|
||||||
|
[CustomPropertyDrawer(typeof(ParameterSyncType))]
|
||||||
|
internal class ParameterSyncTypeDrawer : EnumDrawer<ParameterSyncType>
|
||||||
|
{
|
||||||
|
protected override string localizationPrefix => "params.syncmode";
|
||||||
|
|
||||||
|
protected override Array enumValues => new object[]
|
||||||
|
{
|
||||||
|
ParameterSyncType.NotSynced,
|
||||||
|
ParameterSyncType.Bool,
|
||||||
|
ParameterSyncType.Float,
|
||||||
|
ParameterSyncType.Int,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4d7600669e964ade9c83db369a44e076
|
||||||
|
timeCreated: 1706008016
|
90
Editor/Inspector/Parameters/Parameters.uss
Normal file
90
Editor/Inspector/Parameters/Parameters.uss
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
VisualElement {}
|
||||||
|
|
||||||
|
.ParameterConfig__isPrefix_falseOnly {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ParameterConfig__isPrefix_trueOnly {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ParameterConfig__isPrefix .ParameterConfig__isPrefix_falseOnly {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ParameterConfig__isPrefix .ParameterConfig__isPrefix_trueOnly {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#defaultValueGroup {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
#defaultValueGroup > .unity-base-field__input {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
#defaultValueGroup > .unity-base-field__input > * {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MiniDisplay {
|
||||||
|
flex-direction: row;
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MiniDisplay > * {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MiniDisplay > FloatField {
|
||||||
|
max-width: 60px;
|
||||||
|
flex-grow: 0;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#MiniDisplay > FloatField TextElement {
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#MiniDisplay > Toggle {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ParameterConfigRoot > Toggle .unity-toggle__text {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#UnregisteredParameters #unity-list-view__footer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#UnregisteredParameters Label {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DetectedParameter {
|
||||||
|
flex-direction: row;
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DetectedParameter > Label {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SourceButton {
|
||||||
|
flex-grow:0;
|
||||||
|
align-self: flex-end;
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertically align the reorder handle with the foldout chevron */
|
||||||
|
#Parameters #unity-list-view__reorderable-handle {
|
||||||
|
padding-top: 0;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
11
Editor/Inspector/Parameters/Parameters.uss.meta
Normal file
11
Editor/Inspector/Parameters/Parameters.uss.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d72e507abb5be28499d149b3c22f80bc
|
||||||
|
ScriptedImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
disableValidation: 0
|
37
Editor/Inspector/Parameters/ParametersMainUI.uxml
Normal file
37
Editor/Inspector/Parameters/ParametersMainUI.uxml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<UXML
|
||||||
|
xmlns:ui="UnityEngine.UIElements"
|
||||||
|
xmlns:editor="UnityEditor.UIElements"
|
||||||
|
xmlns:ma="nadena.dev.modular_avatar.core.editor"
|
||||||
|
>
|
||||||
|
<ui:VisualElement name="ListViewContainer">
|
||||||
|
<ui:ListView virtualization-method="DynamicHeight"
|
||||||
|
reorder-mode="Animated"
|
||||||
|
reorderable="true"
|
||||||
|
show-add-remove-footer="true"
|
||||||
|
show-border="true"
|
||||||
|
show-foldout-header="false"
|
||||||
|
name="Parameters"
|
||||||
|
item-height="100"
|
||||||
|
binding-path="parameters"
|
||||||
|
style="flex-grow: 1;"
|
||||||
|
/>
|
||||||
|
</ui:VisualElement>
|
||||||
|
|
||||||
|
<ui:Foldout text="merge_parameter.ui.unregistered_foldout" name="UnregisteredFoldout" value="false" class="ndmf-tr">
|
||||||
|
<!-- The show-add-remove-footer property here somehow also controls the background color
|
||||||
|
of the ListView UI (???). As such, we turn it on here, to get the right theme background color,
|
||||||
|
but then hide the actual footer in USS.
|
||||||
|
-->
|
||||||
|
<ui:ListView
|
||||||
|
reorderable="false"
|
||||||
|
show-add-remove-footer="true"
|
||||||
|
show-border="true"
|
||||||
|
show-foldout-header="false"
|
||||||
|
name="UnregisteredParameters"
|
||||||
|
style="flex-grow: 1;"
|
||||||
|
/>
|
||||||
|
</ui:Foldout>
|
||||||
|
|
||||||
|
<ma:LanguageSwitcherElement/>
|
||||||
|
</UXML>
|
10
Editor/Inspector/Parameters/ParametersMainUI.uxml.meta
Normal file
10
Editor/Inspector/Parameters/ParametersMainUI.uxml.meta
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 00e4e2766c4ae9f4687e98ed34685b4f
|
||||||
|
ScriptedImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
@ -41,6 +41,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
internal static string OverrideLanguage { get; set; } = null;
|
internal static string OverrideLanguage { get; set; } = null;
|
||||||
|
|
||||||
public static Localizer L { get; private set; }
|
public static Localizer L { get; private set; }
|
||||||
|
public static UIElementLocalizer UI;
|
||||||
|
|
||||||
static Localization()
|
static Localization()
|
||||||
{
|
{
|
||||||
@ -57,6 +58,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
});
|
});
|
||||||
|
|
||||||
L = localizer;
|
L = localizer;
|
||||||
|
UI = new UIElementLocalizer(L);
|
||||||
|
|
||||||
LanguagePrefs.RegisterLanguageChangeCallback(typeof(Localization), _ => OnLangChange?.Invoke());
|
LanguagePrefs.RegisterLanguageChangeCallback(typeof(Localization), _ => OnLangChange?.Invoke());
|
||||||
}
|
}
|
||||||
|
90
Editor/Localization/UIElementLocalizer.cs
Normal file
90
Editor/Localization/UIElementLocalizer.cs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using nadena.dev.ndmf.localization;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
|
{
|
||||||
|
internal class UIElementLocalizer
|
||||||
|
{
|
||||||
|
private static Dictionary<Type, Func<VisualElement, Action>> _localizers =
|
||||||
|
new Dictionary<Type, Func<VisualElement, Action>>();
|
||||||
|
|
||||||
|
private readonly Localizer _localizer;
|
||||||
|
|
||||||
|
public UIElementLocalizer(Localizer localizer)
|
||||||
|
{
|
||||||
|
_localizer = localizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Localize(VisualElement elem)
|
||||||
|
{
|
||||||
|
WalkTree(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WalkTree(VisualElement elem)
|
||||||
|
{
|
||||||
|
var ty = elem.GetType();
|
||||||
|
|
||||||
|
if (elem.ClassListContains("ndmf-tr"))
|
||||||
|
{
|
||||||
|
var op = GetLocalizationOperation(ty);
|
||||||
|
if (op != null)
|
||||||
|
{
|
||||||
|
var action = op(elem);
|
||||||
|
LanguagePrefs.RegisterLanguageChangeCallback(elem, _elem => action());
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in elem.Children())
|
||||||
|
{
|
||||||
|
WalkTree(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Func<VisualElement, Action> GetLocalizationOperation(Type ty)
|
||||||
|
{
|
||||||
|
if (!_localizers.TryGetValue(ty, out var action))
|
||||||
|
{
|
||||||
|
PropertyInfo m_label = ty.GetProperty("text") ?? ty.GetProperty("label");
|
||||||
|
|
||||||
|
if (m_label == null)
|
||||||
|
{
|
||||||
|
action = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action = elem =>
|
||||||
|
{
|
||||||
|
var key = m_label.GetValue(elem) as string;
|
||||||
|
|
||||||
|
if (key != null)
|
||||||
|
{
|
||||||
|
return () =>
|
||||||
|
{
|
||||||
|
var new_label = _localizer.GetLocalizedString(key);
|
||||||
|
if (!_localizer.TryGetLocalizedString(key + ":tooltip", out var tooltip))
|
||||||
|
{
|
||||||
|
tooltip = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_label.SetValue(elem, new_label);
|
||||||
|
elem.tooltip = tooltip;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return () => { };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_localizers[ty] = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
Editor/Localization/UIElementLocalizer.cs.meta
Normal file
3
Editor/Localization/UIElementLocalizer.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 37429a0f4f1d4d6e9dc4b27577082ed1
|
||||||
|
timeCreated: 1706179997
|
@ -14,6 +14,13 @@
|
|||||||
"menuinstall.menu_icon_too_large": "The icon set in the menu is too large than 256 pixels.",
|
"menuinstall.menu_icon_too_large": "The icon set in the menu is too large than 256 pixels.",
|
||||||
"menuinstall.menu_icon_uncompressed": "The icon set in the menu is not set for compression.",
|
"menuinstall.menu_icon_uncompressed": "The icon set in the menu is not set for compression.",
|
||||||
"menuinstall.srcmenu": "Menu to Install",
|
"menuinstall.srcmenu": "Menu to Install",
|
||||||
|
|
||||||
|
"params.syncmode.NotSynced": "Animator Only",
|
||||||
|
"params.syncmode.Int": "Int",
|
||||||
|
"params.syncmode.Float": "Float",
|
||||||
|
"params.syncmode.Bool": "Bool",
|
||||||
|
|
||||||
|
"params.__comment__": "=== Unity 2019 only strings ===",
|
||||||
"params.autodetect_header": " Autodetected Parameters ",
|
"params.autodetect_header": " Autodetected Parameters ",
|
||||||
"params.internal": "Internal",
|
"params.internal": "Internal",
|
||||||
"params.pb_prefix": "PhysBones Prefix",
|
"params.pb_prefix": "PhysBones Prefix",
|
||||||
@ -25,10 +32,26 @@
|
|||||||
"params.remapto": "Remap to",
|
"params.remapto": "Remap to",
|
||||||
"params.remapto.tooltip": "Enter a new name for this parameter here to resolve name conflicts",
|
"params.remapto.tooltip": "Enter a new name for this parameter here to resolve name conflicts",
|
||||||
"params.devmode": "Show Prefab Developer Options",
|
"params.devmode": "Show Prefab Developer Options",
|
||||||
"params.syncmode.NotSynced": "Animator Only",
|
|
||||||
"params.syncmode.Int": "Int",
|
"params.__comment1__": "=== Unity 2022 only strings ===",
|
||||||
"params.syncmode.Float": "Float",
|
"merge_parameter.ui.name": "Parameter name",
|
||||||
"params.syncmode.Bool": "Bool",
|
"merge_parameter.ui.prefix": "PhysBone prefix name",
|
||||||
|
"merge_parameter.ui.remapTo": "Change name to",
|
||||||
|
"merge_parameter.ui.remapTo.tooltip": "Enter a new name here to rename this parameter or prefix. This can be used to resolve name conflicts, or to link up multiple gimmicks.",
|
||||||
|
"merge_parameter.ui.defaultValue": "Default",
|
||||||
|
"merge_parameter.ui.defaultValue.tooltip": "This parameter will be set to this value when the avatar is reset or initially worn",
|
||||||
|
"merge_parameter.ui.saved": "Saved",
|
||||||
|
"merge_parameter.ui.saved.tooltip": "If set, this parameter's value will be saved when you change avatars or worlds",
|
||||||
|
"merge_parameter.ui.internalParameter": "Auto Rename",
|
||||||
|
"merge_parameter.ui.internalParameter.tooltip": "If set, this parameter will be automatically renamed to avoid conflicts with other parameters",
|
||||||
|
"merge_parameter.ui.isPrefix": "Is PhysBone Prefix",
|
||||||
|
"merge_parameter.ui.syncType": "Parameter type",
|
||||||
|
"merge_parameter.ui.localOnly": "Local Only",
|
||||||
|
"merge_parameter.ui.localOnly.tooltip": "If set, this parameter will not be synced across the network",
|
||||||
|
"merge_parameter.ui.unregistered_foldout": "Unregistered Parameters",
|
||||||
|
"merge_parameter.ui.add_button": "Add",
|
||||||
|
"merge_parameter.ui.details": "Parameter Configuration",
|
||||||
|
|
||||||
"merge_armature.merge_target": "Merge Target",
|
"merge_armature.merge_target": "Merge Target",
|
||||||
"merge_armature.merge_target.tooltip": "The armature (or subtree) to merge this object into",
|
"merge_armature.merge_target.tooltip": "The armature (or subtree) to merge this object into",
|
||||||
"merge_armature.prefix": "Prefix",
|
"merge_armature.prefix": "Prefix",
|
||||||
|
@ -13,6 +13,13 @@
|
|||||||
"menuinstall.menu_icon_too_large": "メニューに設定されているアイコンが256ピクセルより大きすぎます。",
|
"menuinstall.menu_icon_too_large": "メニューに設定されているアイコンが256ピクセルより大きすぎます。",
|
||||||
"menuinstall.menu_icon_uncompressed": "メニューに設定されているアイコンが圧縮設定されていません。",
|
"menuinstall.menu_icon_uncompressed": "メニューに設定されているアイコンが圧縮設定されていません。",
|
||||||
"menuinstall.srcmenu": "インストールされるメニュー",
|
"menuinstall.srcmenu": "インストールされるメニュー",
|
||||||
|
|
||||||
|
"params.syncmode.NotSynced": "Animatorのみ",
|
||||||
|
"params.syncmode.Int": "Int",
|
||||||
|
"params.syncmode.Float": "Float",
|
||||||
|
"params.syncmode.Bool": "Bool",
|
||||||
|
|
||||||
|
"params.__comment__": "=== Unity 2019 only strings ===",
|
||||||
"params.autodetect_header": " 自動検出されたパラメーター ",
|
"params.autodetect_header": " 自動検出されたパラメーター ",
|
||||||
"params.internal": "内部値",
|
"params.internal": "内部値",
|
||||||
"params.pb_prefix": "PhysBones前置詞",
|
"params.pb_prefix": "PhysBones前置詞",
|
||||||
@ -24,10 +31,26 @@
|
|||||||
"params.remapto": "変更後の名前",
|
"params.remapto": "変更後の名前",
|
||||||
"params.remapto.tooltip": "ここに新しい名前を入れることで、名前かぶりを解消できます",
|
"params.remapto.tooltip": "ここに新しい名前を入れることで、名前かぶりを解消できます",
|
||||||
"params.devmode": "プレハブ開発者向け設定を表示",
|
"params.devmode": "プレハブ開発者向け設定を表示",
|
||||||
"params.syncmode.NotSynced": "Animatorのみ",
|
|
||||||
"params.syncmode.Int": "Int",
|
"params.__comment1__": "=== Unity 2022 only strings ===",
|
||||||
"params.syncmode.Float": "Float",
|
"merge_parameter.ui.name": "パラメーター名",
|
||||||
"params.syncmode.Bool": "Bool",
|
"merge_parameter.ui.prefix": "PhysBone 前置詞名",
|
||||||
|
"merge_parameter.ui.remapTo": "名前を変更",
|
||||||
|
"merge_parameter.ui.remapTo.tooltip": "ここに新しい名前を入れることで、このパラメーターの名前を変更できます。これで名前かぶりを回避したり、あるいはあえて複数のギミックを連動できます。",
|
||||||
|
"merge_parameter.ui.defaultValue": "初期値",
|
||||||
|
"merge_parameter.ui.defaultValue.tooltip": "アバターがリセット、または最初に着た時にこの値が採用されます。",
|
||||||
|
"merge_parameter.ui.saved": "保存する",
|
||||||
|
"merge_parameter.ui.saved.tooltip": "保存されたパラメーターは、アバター変更やワールド移動で保持されます",
|
||||||
|
"merge_parameter.ui.internalParameter": "自動リネーム",
|
||||||
|
"merge_parameter.ui.internalParameter.tooltip": "有効にすると、名前かぶりを回避するために自動的に名前を変更します",
|
||||||
|
"merge_parameter.ui.isPrefix": "PhysBone 前置詞名",
|
||||||
|
"merge_parameter.ui.syncType": "パラメーター型",
|
||||||
|
"merge_parameter.ui.localOnly": "ローカルのみ",
|
||||||
|
"merge_parameter.ui.localOnly.tooltip": "有効にすると、ネットワーク上同期されなくなります",
|
||||||
|
"merge_parameter.ui.unregistered_foldout": "未登録パラメーター",
|
||||||
|
"merge_parameter.ui.add_button": "追加",
|
||||||
|
"merge_parameter.ui.details": "パラメーターの詳細設定",
|
||||||
|
|
||||||
"merge_armature.merge_target": "統合先",
|
"merge_armature.merge_target": "統合先",
|
||||||
"merge_armature.merge_target.tooltip": "このオブジェクトを統合先のアーマチュアに統合します",
|
"merge_armature.merge_target.tooltip": "このオブジェクトを統合先のアーマチュアに統合します",
|
||||||
"merge_armature.prefix": "前置詞",
|
"merge_armature.prefix": "前置詞",
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
using UnityEditor.Animations;
|
using UnityEditor.Animations;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Serialization;
|
||||||
using VRC.SDK3.Avatars.Components;
|
using VRC.SDK3.Avatars.Components;
|
||||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||||
using VRC.SDK3.Dynamics.Contact.Components;
|
using VRC.SDK3.Dynamics.Contact.Components;
|
||||||
@ -20,6 +22,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
public float defaultValue;
|
public float defaultValue;
|
||||||
public bool saved;
|
public bool saved;
|
||||||
|
|
||||||
|
[FormerlySerializedAs("source")] public Object Source;
|
||||||
|
|
||||||
public string MapKey => IsPrefix ? OriginalName + "*" : OriginalName;
|
public string MapKey => IsPrefix ? OriginalName + "*" : OriginalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +100,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
OriginalName = bone.parameter,
|
OriginalName = bone.parameter,
|
||||||
IsPrefix = true,
|
IsPrefix = true,
|
||||||
|
Source = bone,
|
||||||
};
|
};
|
||||||
|
|
||||||
parameters[param.MapKey] = param;
|
parameters[param.MapKey] = param;
|
||||||
@ -112,6 +117,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
OriginalName = contact.parameter,
|
OriginalName = contact.parameter,
|
||||||
IsPrefix = false,
|
IsPrefix = false,
|
||||||
|
Source = contact,
|
||||||
};
|
};
|
||||||
|
|
||||||
parameters[param.MapKey] = param;
|
parameters[param.MapKey] = param;
|
||||||
@ -169,7 +175,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
var param = new DetectedParameter()
|
var param = new DetectedParameter()
|
||||||
{
|
{
|
||||||
OriginalName = name,
|
OriginalName = name,
|
||||||
IsPrefix = false
|
IsPrefix = false,
|
||||||
|
Source = menu,
|
||||||
};
|
};
|
||||||
parameters[param.MapKey] = param;
|
parameters[param.MapKey] = param;
|
||||||
}
|
}
|
||||||
@ -271,7 +278,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
var param = new DetectedParameter()
|
var param = new DetectedParameter()
|
||||||
{
|
{
|
||||||
OriginalName = parameterName,
|
OriginalName = parameterName,
|
||||||
IsPrefix = false
|
IsPrefix = false,
|
||||||
|
Source = controller
|
||||||
};
|
};
|
||||||
parameters[param.MapKey] = param;
|
parameters[param.MapKey] = param;
|
||||||
}
|
}
|
||||||
@ -318,6 +326,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
IsPrefix = false,
|
IsPrefix = false,
|
||||||
OriginalName = name,
|
OriginalName = name,
|
||||||
|
Source = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GetAssetPath(blendTree))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -343,6 +352,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
syncType = map.syncType,
|
syncType = map.syncType,
|
||||||
defaultValue = map.defaultValue,
|
defaultValue = map.defaultValue,
|
||||||
saved = map.saved,
|
saved = map.saved,
|
||||||
|
Source = parametersComponent,
|
||||||
};
|
};
|
||||||
newParams[param.MapKey] = param;
|
newParams[param.MapKey] = param;
|
||||||
continue;
|
continue;
|
||||||
|
@ -14,6 +14,7 @@ namespace nadena.dev.modular_avatar.core
|
|||||||
public bool localOnly;
|
public bool localOnly;
|
||||||
public float defaultValue;
|
public float defaultValue;
|
||||||
public bool saved;
|
public bool saved;
|
||||||
|
public bool? hasDefaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user