253 lines
8.7 KiB
C#
253 lines
8.7 KiB
C#
#if TEXTMESHPRO_SUPPORT
|
|
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using AlicizaX.Localization;
|
|
using AlicizaX.Localization.Editor;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using UnityEditor.Experimental.GraphView;
|
|
|
|
namespace UnityEngine.UI
|
|
{
|
|
internal readonly struct TableSelectionData
|
|
{
|
|
public readonly int Id;
|
|
public readonly string CombineKey; // SectionName/Key → 菜单层级
|
|
public readonly string CombineValue; // SectionName.Key → 存储用
|
|
|
|
public TableSelectionData(int id, string combineKey, string combineValue)
|
|
{
|
|
Id = id;
|
|
CombineKey = combineKey;
|
|
CombineValue = combineValue;
|
|
}
|
|
}
|
|
|
|
[CustomEditor(typeof(UXTextMeshPro), true)]
|
|
[CanEditMultipleObjects]
|
|
internal class UXTextMeshProEditor : TMPro.EditorUtilities.TMP_EditorPanelUI
|
|
{
|
|
private SerializedProperty localizationID;
|
|
private SerializedProperty m_localizationKey;
|
|
|
|
private List<GameLocaizationTable> allTables = new();
|
|
private Dictionary<int, TableSelectionData> allTableNames = new();
|
|
private Dictionary<string, string> previewLabelDic = new();
|
|
private List<string> allSelection = new();
|
|
private int selectedSelectionIndex = 0;
|
|
|
|
public override VisualElement CreateInspectorGUI()
|
|
{
|
|
RefreshAllTables();
|
|
return base.CreateInspectorGUI();
|
|
}
|
|
|
|
private void RefreshAllTables()
|
|
{
|
|
allTables.Clear();
|
|
string[] guids = AssetDatabase.FindAssets("t:GameLocaizationTable");
|
|
foreach (string guid in guids)
|
|
{
|
|
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
|
GameLocaizationTable table = AssetDatabase.LoadAssetAtPath<GameLocaizationTable>(assetPath);
|
|
if (table != null)
|
|
{
|
|
allTables.Add(table);
|
|
}
|
|
}
|
|
|
|
InitAllTables();
|
|
}
|
|
|
|
private void InitAllTables()
|
|
{
|
|
allTableNames.Clear();
|
|
allSelection.Clear();
|
|
previewLabelDic.Clear();
|
|
allSelection.Add("None");
|
|
allTableNames.TryAdd(0, new TableSelectionData(0, "None", string.Empty));
|
|
|
|
var localizationLanguage = allTables.Select(e => e.Languages.Find(t => t.LanguageName == LocalizationConfiguration.Instance.GenerateScriptCodeFirstConfig)).ToList();
|
|
foreach (var localization in localizationLanguage)
|
|
{
|
|
foreach (var item in localization.Strings)
|
|
{
|
|
previewLabelDic.TryAdd(item.Key, item.Value);
|
|
}
|
|
}
|
|
|
|
foreach (var table in allTables)
|
|
{
|
|
foreach (var sheet in table.TableSheet)
|
|
{
|
|
foreach (var selection in sheet.SectionSheet)
|
|
{
|
|
string combineKey = $"{table.name}/{sheet.SectionName}/{selection.Key}";
|
|
string combineValue = $"{sheet.SectionName}.{selection.Key}";
|
|
int id = selection.Id;
|
|
allTableNames.TryAdd(id, new TableSelectionData(id, combineKey, combineValue));
|
|
allSelection.Add(combineKey);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected string GetPreviewLabel()
|
|
{
|
|
return previewLabelDic.TryGetValue(m_localizationKey.stringValue, out var label)
|
|
? label
|
|
: "None";
|
|
}
|
|
|
|
|
|
protected void FindSelectSelection()
|
|
{
|
|
selectedSelectionIndex = 0;
|
|
if (allTableNames.TryGetValue(localizationID.intValue, out TableSelectionData data))
|
|
{
|
|
int idx = allSelection.FindIndex(t => t == data.CombineKey);
|
|
if (idx >= 0)
|
|
selectedSelectionIndex = idx;
|
|
}
|
|
}
|
|
|
|
protected override void OnEnable()
|
|
{
|
|
localizationID = serializedObject.FindProperty("m_localizationID");
|
|
m_localizationKey = serializedObject.FindProperty("m_localizationKey");
|
|
|
|
RefreshAllTables();
|
|
FindSelectSelection();
|
|
|
|
base.OnEnable();
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
serializedObject.Update();
|
|
|
|
// m_localizationKey 只读
|
|
EditorGUI.BeginDisabledGroup(true);
|
|
EditorGUILayout.PropertyField(m_localizationKey);
|
|
EditorGUILayout.LabelField("Text", GetPreviewLabel());
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
// 检查是否找不到对应 ID 的 key
|
|
if (localizationID.intValue > 0 && !allTableNames.ContainsKey(localizationID.intValue))
|
|
{
|
|
EditorGUILayout.HelpBox($"已选择的多语言 Key (ID={localizationID.intValue}) 已被删除,但仍然保留该 ID。", MessageType.Warning);
|
|
}
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
// 下拉按钮
|
|
if (GUILayout.Button(allSelection[selectedSelectionIndex], EditorStyles.popup))
|
|
{
|
|
var mousePos = GUIUtility.GUIToScreenPoint(Event.current.mousePosition);
|
|
SearchWindow.Open(
|
|
new SearchWindowContext(mousePos),
|
|
ScriptableObject.CreateInstance<LocalizationSearchProvider>().Init(allSelection, ApplySelection)
|
|
);
|
|
}
|
|
|
|
serializedObject.ApplyModifiedProperties();
|
|
base.OnInspectorGUI();
|
|
}
|
|
|
|
private void ApplySelection(string selectedKey)
|
|
{
|
|
if (selectedKey == "None")
|
|
{
|
|
localizationID.intValue = 0;
|
|
m_localizationKey.stringValue = string.Empty;
|
|
selectedSelectionIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
foreach (var kvp in allTableNames)
|
|
{
|
|
if (kvp.Value.CombineKey == selectedKey)
|
|
{
|
|
localizationID.intValue = kvp.Value.Id;
|
|
m_localizationKey.stringValue = kvp.Value.CombineValue;
|
|
selectedSelectionIndex = allSelection.IndexOf(kvp.Value.CombineKey);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
serializedObject.ApplyModifiedProperties();
|
|
}
|
|
}
|
|
|
|
internal class LocalizationSearchProvider : ScriptableObject, ISearchWindowProvider
|
|
{
|
|
private List<string> options;
|
|
private System.Action<string> onSelect;
|
|
|
|
public LocalizationSearchProvider Init(List<string> options, System.Action<string> onSelect)
|
|
{
|
|
this.options = options;
|
|
this.onSelect = onSelect;
|
|
return this;
|
|
}
|
|
|
|
public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
|
|
{
|
|
var tree = new List<SearchTreeEntry>
|
|
{
|
|
new SearchTreeGroupEntry(new GUIContent("Localization Keys"), 0)
|
|
};
|
|
|
|
foreach (var option in options)
|
|
{
|
|
if (option == "None")
|
|
{
|
|
tree.Add(new SearchTreeEntry(new GUIContent("None")) { level = 1, userData = "None" });
|
|
}
|
|
else
|
|
{
|
|
// `/` 自动分层
|
|
string[] parts = option.Split('/');
|
|
if (parts.Length == 1)
|
|
{
|
|
tree.Add(new SearchTreeEntry(new GUIContent(parts[0])) { level = 1, userData = option });
|
|
}
|
|
else
|
|
{
|
|
// 前面的部分作为 group
|
|
for (int i = 0; i < parts.Length - 1; i++)
|
|
{
|
|
// 确保 group 唯一
|
|
string groupName = string.Join("/", parts, 0, i + 1);
|
|
if (!tree.Exists(e => e.content.text == parts[i] && e.level == i + 1))
|
|
{
|
|
tree.Add(new SearchTreeGroupEntry(new GUIContent(parts[i])) { level = i + 1 });
|
|
}
|
|
}
|
|
|
|
// 最后部分作为 Entry
|
|
tree.Add(new SearchTreeEntry(new GUIContent(parts[^1])) { level = parts.Length, userData = option });
|
|
}
|
|
}
|
|
}
|
|
|
|
return tree;
|
|
}
|
|
|
|
public bool OnSelectEntry(SearchTreeEntry searchTreeEntry, SearchWindowContext context)
|
|
{
|
|
if (searchTreeEntry.userData is string key)
|
|
{
|
|
onSelect?.Invoke(key);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
#endif
|