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 (#634)
This commit is contained in:
parent
07d61b25b2
commit
86fc302fa5
@ -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 =
|
||||
new Dictionary<Type, Action<VisualElement>>();
|
||||
|
||||
[Obsolete("Use UIElementLocalizer instead")]
|
||||
public static VisualElement Localize(this VisualTreeAsset asset)
|
||||
{
|
||||
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
|
165
Editor/Inspector/Parameters/AvatarParametersEditor.cs
Normal file
165
Editor/Inspector/Parameters/AvatarParametersEditor.cs
Normal file
@ -0,0 +1,165 @@
|
||||
#if MA_VRCSDK3_AVATARS && UNITY_2022_1_OR_NEWER
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using static nadena.dev.modular_avatar.core.editor.Localization;
|
||||
|
||||
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()
|
||||
{
|
||||
EditorGUILayout.HelpBox("Unable to show override changes", MessageType.Info);
|
||||
}
|
||||
|
||||
protected override VisualElement CreateInnerInspectorGUI()
|
||||
{
|
||||
var root = uxml.CloneTree();
|
||||
UI.Localize(root);
|
||||
root.styleSheets.Add(uss);
|
||||
|
||||
listView = root.Q<ListView>("Parameters");
|
||||
|
||||
listView.showBoundCollectionSize = false;
|
||||
listView.virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight;
|
||||
|
||||
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
|
||||
|
||||
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<ParameterSyncType>
|
||||
{
|
||||
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 |
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7fd14c3a2e157c4dba0955d7d64cf5c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
79
Editor/Inspector/Parameters/ParameterConfigDrawer.cs
Normal file
79
Editor/Inspector/Parameters/ParameterConfigDrawer.cs
Normal file
@ -0,0 +1,79 @@
|
||||
#if MA_VRCSDK3_AVATARS && UNITY_2022_1_OR_NEWER
|
||||
|
||||
using System;
|
||||
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
|
||||
{
|
||||
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
|
99
Editor/Inspector/Parameters/Parameters.uss
Normal file
99
Editor/Inspector/Parameters/Parameters.uss
Normal file
@ -0,0 +1,99 @@
|
||||
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: 10px;
|
||||
}
|
||||
|
||||
#ParameterConfigRoot .unity-foldout__input > #unity-checkmark {
|
||||
margin-top: 4px;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
#ParameterConfigRoot .unity-foldout__input > Label {
|
||||
margin-top: 4px;
|
||||
align-self: flex-start;
|
||||
}
|
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;
|
||||
|
||||
public static Localizer L { get; private set; }
|
||||
public static UIElementLocalizer UI;
|
||||
|
||||
static Localization()
|
||||
{
|
||||
@ -57,6 +58,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
});
|
||||
|
||||
L = localizer;
|
||||
UI = new UIElementLocalizer(L);
|
||||
|
||||
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_uncompressed": "The icon set in the menu is not set for compression.",
|
||||
"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.internal": "Internal",
|
||||
"params.pb_prefix": "PhysBones Prefix",
|
||||
@ -25,10 +32,26 @@
|
||||
"params.remapto": "Remap to",
|
||||
"params.remapto.tooltip": "Enter a new name for this parameter here to resolve name conflicts",
|
||||
"params.devmode": "Show Prefab Developer Options",
|
||||
"params.syncmode.NotSynced": "Animator Only",
|
||||
"params.syncmode.Int": "Int",
|
||||
"params.syncmode.Float": "Float",
|
||||
"params.syncmode.Bool": "Bool",
|
||||
|
||||
"params.__comment1__": "=== Unity 2022 only strings ===",
|
||||
"merge_parameter.ui.name": "Parameter name",
|
||||
"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.tooltip": "The armature (or subtree) to merge this object into",
|
||||
"merge_armature.prefix": "Prefix",
|
||||
|
@ -13,6 +13,13 @@
|
||||
"menuinstall.menu_icon_too_large": "メニューに設定されているアイコンが256ピクセルより大きすぎます。",
|
||||
"menuinstall.menu_icon_uncompressed": "メニューに設定されているアイコンが圧縮設定されていません。",
|
||||
"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.internal": "内部値",
|
||||
"params.pb_prefix": "PhysBones前置詞",
|
||||
@ -24,10 +31,26 @@
|
||||
"params.remapto": "変更後の名前",
|
||||
"params.remapto.tooltip": "ここに新しい名前を入れることで、名前かぶりを解消できます",
|
||||
"params.devmode": "プレハブ開発者向け設定を表示",
|
||||
"params.syncmode.NotSynced": "Animatorのみ",
|
||||
"params.syncmode.Int": "Int",
|
||||
"params.syncmode.Float": "Float",
|
||||
"params.syncmode.Bool": "Bool",
|
||||
|
||||
"params.__comment1__": "=== Unity 2022 only strings ===",
|
||||
"merge_parameter.ui.name": "パラメーター名",
|
||||
"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.tooltip": "このオブジェクトを統合先のアーマチュアに統合します",
|
||||
"merge_armature.prefix": "前置詞",
|
||||
|
@ -3,8 +3,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||
using VRC.SDK3.Dynamics.Contact.Components;
|
||||
@ -20,6 +22,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
public float defaultValue;
|
||||
public bool saved;
|
||||
|
||||
[FormerlySerializedAs("source")] public Object Source;
|
||||
|
||||
public string MapKey => IsPrefix ? OriginalName + "*" : OriginalName;
|
||||
}
|
||||
|
||||
@ -96,6 +100,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
OriginalName = bone.parameter,
|
||||
IsPrefix = true,
|
||||
Source = bone,
|
||||
};
|
||||
|
||||
parameters[param.MapKey] = param;
|
||||
@ -112,6 +117,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
OriginalName = contact.parameter,
|
||||
IsPrefix = false,
|
||||
Source = contact,
|
||||
};
|
||||
|
||||
parameters[param.MapKey] = param;
|
||||
@ -169,7 +175,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
var param = new DetectedParameter()
|
||||
{
|
||||
OriginalName = name,
|
||||
IsPrefix = false
|
||||
IsPrefix = false,
|
||||
Source = menu,
|
||||
};
|
||||
parameters[param.MapKey] = param;
|
||||
}
|
||||
@ -271,7 +278,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
var param = new DetectedParameter()
|
||||
{
|
||||
OriginalName = parameterName,
|
||||
IsPrefix = false
|
||||
IsPrefix = false,
|
||||
Source = controller
|
||||
};
|
||||
parameters[param.MapKey] = param;
|
||||
}
|
||||
@ -318,6 +326,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
IsPrefix = false,
|
||||
OriginalName = name,
|
||||
Source = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GetAssetPath(blendTree))
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -338,11 +347,12 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
if (map.internalParameter || map.syncType == ParameterSyncType.NotSynced) continue;
|
||||
var param = new DetectedParameter()
|
||||
{
|
||||
OriginalName = map.remapTo,
|
||||
OriginalName = string.IsNullOrWhiteSpace(map.remapTo) ? map.nameOrPrefix : map.remapTo,
|
||||
IsPrefix = map.isPrefix,
|
||||
syncType = map.syncType,
|
||||
defaultValue = map.defaultValue,
|
||||
saved = map.saved,
|
||||
Source = parametersComponent,
|
||||
};
|
||||
newParams[param.MapKey] = param;
|
||||
continue;
|
||||
|
Loading…
Reference in New Issue
Block a user