com.alicizax.unity.ui.exten.../Editor/UX/UXTextMeshPro/UXTextMeshProEditor.cs

262 lines
9.1 KiB
C#
Raw Normal View History

2025-08-06 10:56:25 +08:00
#if TEXTMESHPRO_SUPPORT
2025-02-07 16:15:34 +08:00
2025-09-25 11:09:09 +08:00
using System.Collections.Generic;
using System.Linq;
using AlicizaX.Localization;
using AlicizaX.Localization.Editor;
2025-08-06 10:56:25 +08:00
using UnityEditor;
2025-09-25 11:09:09 +08:00
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.Experimental.GraphView;
2025-02-07 16:15:34 +08:00
namespace UnityEngine.UI
{
2025-09-25 11:09:09 +08:00
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;
}
}
2025-02-07 16:15:34 +08:00
[CustomEditor(typeof(UXTextMeshPro), true)]
[CanEditMultipleObjects]
2025-07-28 20:52:34 +08:00
internal class UXTextMeshProEditor : TMPro.EditorUtilities.TMP_EditorPanelUI
2025-02-07 16:15:34 +08:00
{
private SerializedProperty localizationID;
2025-09-25 11:09:09 +08:00
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;
}
}
2025-02-07 16:15:34 +08:00
2025-10-15 13:05:27 +08:00
protected void RefreshKeyValue()
{
if (allTableNames.TryGetValue(localizationID.intValue, out TableSelectionData data))
{
m_localizationKey.stringValue = data.CombineValue;
serializedObject.ApplyModifiedProperties();
}
}
2025-02-07 16:15:34 +08:00
protected override void OnEnable()
{
localizationID = serializedObject.FindProperty("m_localizationID");
2025-09-25 11:09:09 +08:00
m_localizationKey = serializedObject.FindProperty("m_localizationKey");
RefreshAllTables();
FindSelectSelection();
2025-10-15 13:05:27 +08:00
RefreshKeyValue();
2025-02-07 16:15:34 +08:00
base.OnEnable();
}
public override void OnInspectorGUI()
{
serializedObject.Update();
2025-09-25 11:09:09 +08:00
// 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);
}
2025-02-07 16:15:34 +08:00
2025-09-25 11:09:09 +08:00
EditorGUILayout.Space();
2025-03-13 16:40:06 +08:00
2025-09-25 11:09:09 +08:00
// 下拉按钮
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)
);
}
2025-02-07 16:15:34 +08:00
serializedObject.ApplyModifiedProperties();
base.OnInspectorGUI();
}
2025-09-25 11:09:09 +08:00
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;
}
2025-02-07 16:15:34 +08:00
}
}
2025-08-06 10:56:25 +08:00
#endif