UI系统优化
This commit is contained in:
@@ -4,6 +4,7 @@ using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using BaseGames.Dialogue;
|
||||
using BaseGames.Localization;
|
||||
|
||||
namespace BaseGames.Editor.Modules
|
||||
{
|
||||
@@ -81,7 +82,7 @@ namespace BaseGames.Editor.Modules
|
||||
// 名称:优先显示本地化实际文本,回退到 key 本身
|
||||
string nameDisplay = string.IsNullOrEmpty(a.nameKey)
|
||||
? "(未设置)"
|
||||
: (BaseGames.Localization.LocalizationManager.GetEditorPreview(a.nameKey, "Dialogue") ?? a.nameKey);
|
||||
: (BaseGames.Localization.LocalizationManager.GetEditorPreview(a.nameKey, LocalizationTable.Dialogue) ?? a.nameKey);
|
||||
SkillModule.AddChip(card, "名称", nameDisplay);
|
||||
if (!string.IsNullOrEmpty(a.nameKey))
|
||||
SkillModule.AddChip(card, "名称 Key", a.nameKey);
|
||||
|
||||
@@ -6,6 +6,7 @@ using UnityEngine.UIElements;
|
||||
using BaseGames.Dialogue;
|
||||
using BaseGames.Editor.Dialogue;
|
||||
using BaseGames.Editor.Shared;
|
||||
using BaseGames.Localization;
|
||||
|
||||
namespace BaseGames.Editor.Modules
|
||||
{
|
||||
@@ -97,9 +98,9 @@ namespace BaseGames.Editor.Modules
|
||||
};
|
||||
}
|
||||
|
||||
filterRow.Add(QuestModule.MakeFilterChip("有变体", v => { filterVariants = v; RebuildFilter(); }));
|
||||
filterRow.Add(QuestModule.MakeFilterChip("有分支", v => { filterBranches = v; RebuildFilter(); }));
|
||||
filterRow.Add(QuestModule.MakeFilterChip("无语音", v => { filterNoVoice = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("有变体", v => { filterVariants = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("有分支", v => { filterBranches = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("无语音", v => { filterNoVoice = v; RebuildFilter(); }));
|
||||
|
||||
container.Add(_listPane);
|
||||
_listPane.Refresh();
|
||||
@@ -219,7 +220,7 @@ namespace BaseGames.Editor.Modules
|
||||
string speakerKey = line.ResolvedNameKey;
|
||||
if (!string.IsNullOrEmpty(speakerKey))
|
||||
{
|
||||
var speakerResolved = BaseGames.Localization.LocalizationManager.GetEditorPreview(speakerKey, "Dialogue");
|
||||
var speakerResolved = BaseGames.Localization.LocalizationManager.GetEditorPreview(speakerKey, LocalizationTable.Dialogue);
|
||||
bool speakerMissing = speakerResolved == null;
|
||||
string speakerText = speakerMissing ? speakerKey : speakerResolved;
|
||||
var spk = new Label(speakerText + ":");
|
||||
@@ -255,7 +256,7 @@ namespace BaseGames.Editor.Modules
|
||||
}
|
||||
else
|
||||
{
|
||||
var resolved = BaseGames.Localization.LocalizationManager.GetEditorPreview(line.textKey, "Dialogue");
|
||||
var resolved = BaseGames.Localization.LocalizationManager.GetEditorPreview(line.textKey, LocalizationTable.Dialogue);
|
||||
if (resolved != null)
|
||||
{
|
||||
textPreview = resolved;
|
||||
@@ -454,7 +455,7 @@ namespace BaseGames.Editor.Modules
|
||||
string GetLoc(string key)
|
||||
{
|
||||
if (locCache.TryGetValue(key, out var v)) return v;
|
||||
v = BaseGames.Localization.LocalizationManager.GetEditorPreview(key, "Dialogue");
|
||||
v = BaseGames.Localization.LocalizationManager.GetEditorPreview(key, LocalizationTable.Dialogue);
|
||||
locCache[key] = v;
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -74,9 +74,9 @@ namespace BaseGames.Editor.Modules
|
||||
};
|
||||
}
|
||||
|
||||
filterRow.Add(QuestModule.MakeFilterChip("可重复", v => { filterRepeatable = v; RebuildFilter(); }));
|
||||
filterRow.Add(QuestModule.MakeFilterChip("无条件", v => { filterNoCondition = v; RebuildFilter(); }));
|
||||
filterRow.Add(QuestModule.MakeFilterChip("无动作", v => { filterNoAction = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("可重复", v => { filterRepeatable = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("无条件", v => { filterNoCondition = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("无动作", v => { filterNoAction = v; RebuildFilter(); }));
|
||||
|
||||
container.Add(_listPane);
|
||||
_listPane.Refresh();
|
||||
|
||||
11
Assets/_Game/Scripts/Editor/Modules/EventChainModule.cs.meta
Normal file
11
Assets/_Game/Scripts/Editor/Modules/EventChainModule.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c65f27c4b0792904087283cc4e901118
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -81,8 +81,8 @@ namespace BaseGames.Editor.Modules
|
||||
filterRow.style.paddingBottom = 3;
|
||||
container.Add(filterRow);
|
||||
|
||||
filterRow.Add(QuestModule.MakeFilterChip("仅孤立", v => { _filterOrphan = v; RebuildList(); }));
|
||||
filterRow.Add(QuestModule.MakeFilterChip("仅未注册", v => { _filterUnregistered = v; RebuildList(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("仅孤立", v => { _filterOrphan = v; RebuildList(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("仅未注册", v => { _filterUnregistered = v; RebuildList(); }));
|
||||
|
||||
// 列表 ScrollView
|
||||
var scroll = new ScrollView();
|
||||
|
||||
11
Assets/_Game/Scripts/Editor/Modules/FlagAuditModule.cs.meta
Normal file
11
Assets/_Game/Scripts/Editor/Modules/FlagAuditModule.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de4bd4ec2a39e3c4e89649069cb0f6e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
11
Assets/_Game/Scripts/Editor/Modules/IdCodegenModule.cs.meta
Normal file
11
Assets/_Game/Scripts/Editor/Modules/IdCodegenModule.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cbbfd509dce2f0489febf07574b652a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
572
Assets/_Game/Scripts/Editor/Modules/LocalizationAuditModule.cs
Normal file
572
Assets/_Game/Scripts/Editor/Modules/LocalizationAuditModule.cs
Normal file
@@ -0,0 +1,572 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using BaseGames.Localization;
|
||||
|
||||
namespace BaseGames.Editor.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// DataHub 本地化审计模块。
|
||||
/// 通过 <see cref="ILocalizableAsset"/> 接口扫描项目中所有 ScriptableObject 的本地化 Key,
|
||||
/// 与 Resources/Localization/ JSON 表比对,列出缺失条目和命名不规范条目。
|
||||
///
|
||||
/// 菜单入口:DataHub → "本地化审计"
|
||||
/// </summary>
|
||||
public class LocalizationAuditModule : IDataModule, IDataModuleOrdered
|
||||
{
|
||||
public string ModuleId => "localization-audit";
|
||||
public string DisplayName => "本地化审计";
|
||||
public string IconName => "d_UnityEditor.InspectorWindow";
|
||||
public int DisplayOrder => 135;
|
||||
|
||||
// Key 命名规范:UPPER_SNAKE_CASE(大写字母、数字、下划线,首字符必须是大写字母)
|
||||
private static readonly Regex s_keyPattern = new(@"^[A-Z][A-Z0-9_]*$", RegexOptions.Compiled);
|
||||
|
||||
// ── 数据 ─────────────────────────────────────────────────────────────
|
||||
|
||||
private readonly List<AuditIssue> _issues = new();
|
||||
private readonly List<NamingIssue> _namingIssues = new();
|
||||
private readonly List<Language> _availableLanguages = new();
|
||||
private int _totalLanguageCount;
|
||||
private bool _hasScanned;
|
||||
|
||||
private class AuditIssue
|
||||
{
|
||||
public string key;
|
||||
public string table;
|
||||
public string soPath;
|
||||
public string fieldName;
|
||||
public UnityEngine.Object asset;
|
||||
public readonly List<string> missingLanguages = new();
|
||||
}
|
||||
|
||||
private class NamingIssue
|
||||
{
|
||||
public string key;
|
||||
public string table;
|
||||
public string soPath;
|
||||
public string fieldName;
|
||||
public UnityEngine.Object asset;
|
||||
}
|
||||
|
||||
// ── UI 引用 ───────────────────────────────────────────────────────────
|
||||
|
||||
private VisualElement _listItems;
|
||||
private Label _summaryLabel;
|
||||
private VisualElement _detailRoot;
|
||||
private VisualElement _namingSection;
|
||||
private bool _filterMissingAll, _filterMissingPartial, _filterNamingIssue;
|
||||
private string _filterTableName = "";
|
||||
|
||||
// ── IDataModule ───────────────────────────────────────────────────────
|
||||
|
||||
public void Initialize() { }
|
||||
|
||||
public void BuildListPane(VisualElement container, Action<UnityEngine.Object> onSelected)
|
||||
{
|
||||
// 扫描 + 导出 按钮行
|
||||
var btnRow = new VisualElement();
|
||||
btnRow.style.flexDirection = FlexDirection.Row;
|
||||
btnRow.style.marginTop = 8;
|
||||
btnRow.style.marginLeft = 8;
|
||||
btnRow.style.marginRight = 8;
|
||||
btnRow.style.marginBottom = 4;
|
||||
container.Add(btnRow);
|
||||
|
||||
var scanBtn = new Button(RunScan) { text = "🔍 扫描本地化缺失" };
|
||||
scanBtn.style.flexGrow = 1;
|
||||
scanBtn.style.marginRight = 4;
|
||||
btnRow.Add(scanBtn);
|
||||
|
||||
var exportBtn = new Button(ExportReport) { text = "📄 导出报告" };
|
||||
exportBtn.style.width = 90;
|
||||
btnRow.Add(exportBtn);
|
||||
|
||||
_summaryLabel = new Label("尚未扫描,点击左侧按钮开始。");
|
||||
_summaryLabel.style.fontSize = 10;
|
||||
_summaryLabel.style.opacity = 0.6f;
|
||||
_summaryLabel.style.paddingLeft = 10;
|
||||
_summaryLabel.style.marginBottom = 4;
|
||||
container.Add(_summaryLabel);
|
||||
|
||||
// 过滤行
|
||||
var filterRow = new VisualElement();
|
||||
filterRow.style.flexDirection = FlexDirection.Row;
|
||||
filterRow.style.flexWrap = Wrap.Wrap;
|
||||
filterRow.style.paddingLeft = 6;
|
||||
filterRow.style.paddingRight = 6;
|
||||
filterRow.style.paddingBottom = 3;
|
||||
container.Add(filterRow);
|
||||
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("全部语言缺失", v => { _filterMissingAll = v; RebuildList(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("部分语言缺失", v => { _filterMissingPartial = v; RebuildList(); }));
|
||||
// "命名不规范"Chip 现在只控制命名折叠区展开/折叠,不再隐藏缺失列表
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("展开命名问题", v => { _filterNamingIssue = v; RebuildList(); }));
|
||||
|
||||
// 表名过滤输入框
|
||||
var tableField = new TextField("表名过滤") { value = "" };
|
||||
tableField.style.paddingLeft = 6;
|
||||
tableField.style.paddingRight = 6;
|
||||
tableField.style.marginBottom = 3;
|
||||
tableField.RegisterValueChangedCallback(e =>
|
||||
{
|
||||
_filterTableName = e.newValue?.Trim() ?? "";
|
||||
RebuildList();
|
||||
});
|
||||
container.Add(tableField);
|
||||
|
||||
var scroll = new ScrollView { style = { flexGrow = 1 } };
|
||||
container.Add(scroll);
|
||||
|
||||
_listItems = new VisualElement();
|
||||
scroll.Add(_listItems);
|
||||
|
||||
_namingSection = new VisualElement();
|
||||
scroll.Add(_namingSection);
|
||||
}
|
||||
|
||||
public void BuildDetailPane(VisualElement container, UnityEngine.Object selected)
|
||||
{
|
||||
_detailRoot = container;
|
||||
RebuildDetail(null);
|
||||
}
|
||||
|
||||
public void OnActivated() { }
|
||||
|
||||
// ── 扫描 ──────────────────────────────────────────────────────────────
|
||||
|
||||
private void RunScan()
|
||||
{
|
||||
_issues.Clear();
|
||||
_namingIssues.Clear();
|
||||
_availableLanguages.Clear();
|
||||
LocalizationManager.ClearEditorPreviewCache();
|
||||
_hasScanned = true;
|
||||
|
||||
DiscoverLanguages();
|
||||
_totalLanguageCount = _availableLanguages.Count;
|
||||
|
||||
ScanAllLocalizableAssets();
|
||||
|
||||
int total = _issues.Count;
|
||||
int misAll = _issues.Count(i => i.missingLanguages.Count == _totalLanguageCount);
|
||||
int naming = _namingIssues.Count;
|
||||
|
||||
_summaryLabel.text = total == 0 && naming == 0
|
||||
? $"✅ 全部通过!已检查 {_totalLanguageCount} 个语言。"
|
||||
: $"⚠ {total} 个缺失问题(全语言缺失 {misAll} 个),{naming} 个命名不规范。";
|
||||
|
||||
RebuildList();
|
||||
}
|
||||
|
||||
// ── 语言发现 ──────────────────────────────────────────────────────────
|
||||
|
||||
private void DiscoverLanguages()
|
||||
{
|
||||
string root = "Assets/Resources/Localization";
|
||||
if (!AssetDatabase.IsValidFolder(root)) return;
|
||||
|
||||
foreach (var langFolder in AssetDatabase.GetSubFolders(root))
|
||||
{
|
||||
string langName = Path.GetFileName(langFolder);
|
||||
if (Enum.TryParse<Language>(langName, out var lang))
|
||||
_availableLanguages.Add(lang);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 通用 ILocalizableAsset 扫描 ───────────────────────────────────────
|
||||
|
||||
private void ScanAllLocalizableAssets()
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets("t:ScriptableObject");
|
||||
int total = guids.Length;
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < total; i++)
|
||||
{
|
||||
if (EditorUtility.DisplayCancelableProgressBar(
|
||||
"本地化审计", $"扫描中… ({i + 1}/{total})", (float)(i + 1) / total))
|
||||
break;
|
||||
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
var so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
|
||||
if (so == null || so is not ILocalizableAsset loc) continue;
|
||||
|
||||
foreach (var keyRef in loc.GetLocalizationKeys())
|
||||
{
|
||||
CheckKey(so, keyRef.Key, keyRef.Table, keyRef.FieldName);
|
||||
CheckKeyNamingConvention(so, keyRef.Key, keyRef.Table, keyRef.FieldName, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
}
|
||||
|
||||
// ── 导出审计报告 ──────────────────────────────────────────────────────
|
||||
|
||||
private void ExportReport()
|
||||
{
|
||||
if (!_hasScanned)
|
||||
{
|
||||
EditorUtility.DisplayDialog("导出报告", "请先执行扫描,再导出报告。", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||
string dir = Path.Combine(Application.dataPath, "_Game", "Localization");
|
||||
Directory.CreateDirectory(dir);
|
||||
string filePath = Path.Combine(dir, $"AuditReport_{timestamp}.txt");
|
||||
|
||||
using var sw = new StreamWriter(filePath, false, System.Text.Encoding.UTF8);
|
||||
|
||||
sw.WriteLine("====================================================");
|
||||
sw.WriteLine(" 本地化审计报告");
|
||||
sw.WriteLine($" 生成时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
||||
sw.WriteLine("====================================================");
|
||||
sw.WriteLine();
|
||||
sw.WriteLine($"缺失条目:{_issues.Count} 个");
|
||||
sw.WriteLine($"命名不规范:{_namingIssues.Count} 个");
|
||||
sw.WriteLine();
|
||||
|
||||
if (_issues.Count > 0)
|
||||
{
|
||||
sw.WriteLine("── 缺失翻译 ────────────────────────────────────────");
|
||||
foreach (var issue in _issues)
|
||||
{
|
||||
sw.WriteLine($" [{issue.table}] {issue.key}");
|
||||
sw.WriteLine($" 字段:{issue.fieldName}");
|
||||
sw.WriteLine($" 路径:{issue.soPath}");
|
||||
sw.WriteLine($" 缺失语言:{string.Join(", ", issue.missingLanguages)}");
|
||||
sw.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
if (_namingIssues.Count > 0)
|
||||
{
|
||||
sw.WriteLine("── 命名不规范(应为 UPPER_SNAKE_CASE)────────────────");
|
||||
foreach (var ni in _namingIssues)
|
||||
{
|
||||
sw.WriteLine($" [{ni.table}] {ni.key}");
|
||||
sw.WriteLine($" 字段:{ni.fieldName}");
|
||||
sw.WriteLine($" 路径:{ni.soPath}");
|
||||
sw.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
sw.WriteLine("====================================================");
|
||||
sw.Flush();
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
string relPath = $"Assets/_Game/Localization/AuditReport_{timestamp}.txt";
|
||||
var asset = AssetDatabase.LoadAssetAtPath<TextAsset>(relPath);
|
||||
if (asset != null) EditorGUIUtility.PingObject(asset);
|
||||
|
||||
EditorUtility.DisplayDialog("导出成功",
|
||||
$"报告已保存至:\n{filePath}", "打开文件夹");
|
||||
EditorUtility.RevealInFinder(filePath);
|
||||
}
|
||||
|
||||
// ── Key 检查 ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
private void CheckKey(UnityEngine.Object asset, string key, string table, string fieldName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key)) return;
|
||||
|
||||
var issue = new AuditIssue
|
||||
{
|
||||
key = key,
|
||||
table = table,
|
||||
fieldName = fieldName,
|
||||
soPath = AssetDatabase.GetAssetPath(asset),
|
||||
asset = asset,
|
||||
};
|
||||
|
||||
foreach (var lang in _availableLanguages)
|
||||
{
|
||||
var dict = LocalizationManager.GetEditorTable(lang, table);
|
||||
if (dict == null || !dict.ContainsKey(key))
|
||||
issue.missingLanguages.Add(lang.ToString());
|
||||
}
|
||||
|
||||
if (issue.missingLanguages.Count > 0)
|
||||
_issues.Add(issue);
|
||||
}
|
||||
|
||||
private void CheckKeyNamingConvention(UnityEngine.Object asset, string key, string table,
|
||||
string fieldName, string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key)) return;
|
||||
if (s_keyPattern.IsMatch(key)) return;
|
||||
|
||||
_namingIssues.Add(new NamingIssue
|
||||
{
|
||||
key = key,
|
||||
table = table,
|
||||
fieldName = fieldName,
|
||||
soPath = path,
|
||||
asset = asset,
|
||||
});
|
||||
}
|
||||
|
||||
// ── 列表 / 详情 UI ────────────────────────────────────────────────────
|
||||
|
||||
private AuditIssue _selectedIssue;
|
||||
|
||||
private void RebuildList()
|
||||
{
|
||||
_listItems.Clear();
|
||||
_namingSection.Clear();
|
||||
if (!_hasScanned) return;
|
||||
|
||||
// ── 缺失问题列表(始终显示,不受命名 Chip 影响)─────────────────
|
||||
var filtered = _issues.AsEnumerable();
|
||||
|
||||
if (_filterMissingAll)
|
||||
filtered = filtered.Where(i => i.missingLanguages.Count == _totalLanguageCount);
|
||||
else if (_filterMissingPartial)
|
||||
filtered = filtered.Where(i => i.missingLanguages.Count > 0 && i.missingLanguages.Count < _totalLanguageCount);
|
||||
|
||||
if (!string.IsNullOrEmpty(_filterTableName))
|
||||
filtered = filtered.Where(i => i.table.IndexOf(_filterTableName, StringComparison.OrdinalIgnoreCase) >= 0);
|
||||
|
||||
var list = filtered.ToList();
|
||||
|
||||
if (list.Count == 0)
|
||||
{
|
||||
_listItems.Add(new Label("无缺失问题或无匹配结果。") { style = { paddingLeft = 10, opacity = 0.5f } });
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var issue in list)
|
||||
{
|
||||
var row = BuildMissingRow(issue);
|
||||
_listItems.Add(row);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 命名不规范列表(独立折叠区)────────────────────────────────
|
||||
if (_namingIssues.Count > 0)
|
||||
{
|
||||
var foldout = new Foldout
|
||||
{
|
||||
text = $"命名不规范 Key({_namingIssues.Count} 个)",
|
||||
value = _filterNamingIssue,
|
||||
};
|
||||
foldout.style.paddingLeft = 4;
|
||||
_namingSection.Add(foldout);
|
||||
|
||||
var namingFiltered = _namingIssues.AsEnumerable();
|
||||
if (!string.IsNullOrEmpty(_filterTableName))
|
||||
namingFiltered = namingFiltered.Where(i => i.table.IndexOf(_filterTableName, StringComparison.OrdinalIgnoreCase) >= 0);
|
||||
|
||||
foreach (var ni in namingFiltered)
|
||||
{
|
||||
var row = new VisualElement();
|
||||
row.style.flexDirection = FlexDirection.Row;
|
||||
row.style.paddingLeft = 8;
|
||||
row.style.paddingRight = 8;
|
||||
row.style.paddingTop = 3;
|
||||
row.style.paddingBottom = 3;
|
||||
row.style.borderBottomWidth = 1;
|
||||
row.style.borderBottomColor = new StyleColor(new Color(0.3f, 0.3f, 0.3f, 0.4f));
|
||||
row.style.backgroundColor = new StyleColor(new Color(0.2f, 0.2f, 0.45f, 0.25f));
|
||||
|
||||
var capturedNi = ni;
|
||||
row.RegisterCallback<ClickEvent>(_ =>
|
||||
{
|
||||
if (capturedNi.asset != null)
|
||||
{
|
||||
EditorGUIUtility.PingObject(capturedNi.asset);
|
||||
Selection.activeObject = capturedNi.asset;
|
||||
}
|
||||
RebuildNamingDetail(capturedNi);
|
||||
});
|
||||
|
||||
var lbl = new Label($"[{ni.table}] {ni.key} ({ni.fieldName})");
|
||||
lbl.style.flexGrow = 1;
|
||||
lbl.style.fontSize = 11;
|
||||
row.Add(lbl);
|
||||
|
||||
var hint = new Label("应为 UPPER_SNAKE_CASE");
|
||||
hint.style.fontSize = 10;
|
||||
hint.style.opacity = 0.6f;
|
||||
row.Add(hint);
|
||||
|
||||
foldout.Add(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private VisualElement BuildMissingRow(AuditIssue issue)
|
||||
{
|
||||
var row = new VisualElement();
|
||||
row.style.flexDirection = FlexDirection.Row;
|
||||
row.style.paddingLeft = 8;
|
||||
row.style.paddingRight = 8;
|
||||
row.style.paddingTop = 4;
|
||||
row.style.paddingBottom = 4;
|
||||
row.style.borderBottomWidth = 1;
|
||||
row.style.borderBottomColor = new StyleColor(new Color(0.3f, 0.3f, 0.3f, 0.4f));
|
||||
|
||||
var captured = issue;
|
||||
row.RegisterCallback<ClickEvent>(_ =>
|
||||
{
|
||||
_selectedIssue = captured;
|
||||
RebuildDetail(captured);
|
||||
if (captured.asset != null)
|
||||
EditorGUIUtility.PingObject(captured.asset);
|
||||
});
|
||||
|
||||
bool allMissing = issue.missingLanguages.Count == _totalLanguageCount;
|
||||
row.style.backgroundColor = new StyleColor(allMissing
|
||||
? new Color(0.45f, 0.15f, 0.05f, 0.35f)
|
||||
: new Color(0.40f, 0.35f, 0.00f, 0.25f));
|
||||
|
||||
var left = new Label($"[{issue.table}] {issue.key}");
|
||||
left.style.flexGrow = 1;
|
||||
left.style.fontSize = 11;
|
||||
left.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
row.Add(left);
|
||||
|
||||
var right = new Label(string.Join(", ", issue.missingLanguages));
|
||||
right.style.fontSize = 10;
|
||||
right.style.opacity = 0.7f;
|
||||
row.Add(right);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
private void RebuildDetail(AuditIssue issue)
|
||||
{
|
||||
if (_detailRoot == null) return;
|
||||
_detailRoot.Clear();
|
||||
|
||||
if (issue == null)
|
||||
{
|
||||
_detailRoot.Add(new Label("← 选择左侧条目查看详情。") { style = { paddingLeft = 16, paddingTop = 16, opacity = 0.5f } });
|
||||
return;
|
||||
}
|
||||
|
||||
var title = new Label($"Key:{issue.key}");
|
||||
title.style.fontSize = 14;
|
||||
title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
title.style.paddingLeft = 12;
|
||||
title.style.paddingTop = 10;
|
||||
title.style.paddingBottom = 6;
|
||||
_detailRoot.Add(title);
|
||||
|
||||
AddDetailRow(_detailRoot, "表名", issue.table);
|
||||
AddDetailRow(_detailRoot, "字段", issue.fieldName);
|
||||
AddDetailRow(_detailRoot, "资产路径", issue.soPath);
|
||||
|
||||
_detailRoot.Add(new Label("缺失语言:") { style = { paddingLeft = 12, paddingTop = 8, fontSize = 11, unityFontStyleAndWeight = FontStyle.Bold } });
|
||||
foreach (var lang in issue.missingLanguages)
|
||||
_detailRoot.Add(new Label($" • {lang}") { style = { paddingLeft = 20, fontSize = 11 } });
|
||||
|
||||
_detailRoot.Add(new VisualElement { style = { height = 8 } });
|
||||
var btnRow = new VisualElement { style = { flexDirection = FlexDirection.Row, paddingLeft = 10, paddingRight = 10 } };
|
||||
_detailRoot.Add(btnRow);
|
||||
|
||||
var pingBtn = new Button(() =>
|
||||
{
|
||||
if (issue.asset != null)
|
||||
{
|
||||
EditorGUIUtility.PingObject(issue.asset);
|
||||
Selection.activeObject = issue.asset;
|
||||
}
|
||||
}) { text = "定位 SO 资产", style = { flexGrow = 1, marginRight = 4 } };
|
||||
btnRow.Add(pingBtn);
|
||||
|
||||
var copyBtn = new Button(() =>
|
||||
{
|
||||
EditorGUIUtility.systemCopyBuffer = issue.key;
|
||||
Debug.Log($"[LocalizationAudit] 已复制 Key:{issue.key}");
|
||||
}) { text = "复制 Key", style = { flexGrow = 1 } };
|
||||
btnRow.Add(copyBtn);
|
||||
|
||||
foreach (var lang in issue.missingLanguages)
|
||||
{
|
||||
var capturedLang = lang;
|
||||
var openBtn = new Button(() => PingTableFile(capturedLang, issue.table))
|
||||
{
|
||||
text = $"打开 {lang}/{issue.table}.json",
|
||||
style = { marginTop = 4, marginLeft = 10, marginRight = 10 },
|
||||
};
|
||||
_detailRoot.Add(openBtn);
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildNamingDetail(NamingIssue ni)
|
||||
{
|
||||
if (_detailRoot == null) return;
|
||||
_detailRoot.Clear();
|
||||
|
||||
var title = new Label($"命名不规范:{ni.key}");
|
||||
title.style.fontSize = 14;
|
||||
title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
title.style.paddingLeft = 12;
|
||||
title.style.paddingTop = 10;
|
||||
title.style.paddingBottom = 6;
|
||||
_detailRoot.Add(title);
|
||||
|
||||
AddDetailRow(_detailRoot, "表名", ni.table);
|
||||
AddDetailRow(_detailRoot, "字段", ni.fieldName);
|
||||
AddDetailRow(_detailRoot, "资产路径", ni.soPath);
|
||||
|
||||
_detailRoot.Add(new Label("规范要求:UPPER_SNAKE_CASE(如 QUEST_FIND_HERB_NAME)")
|
||||
{ style = { paddingLeft = 12, paddingTop = 8, fontSize = 11, opacity = 0.7f } });
|
||||
|
||||
_detailRoot.Add(new VisualElement { style = { height = 8 } });
|
||||
var pingBtn = new Button(() =>
|
||||
{
|
||||
if (ni.asset != null)
|
||||
{
|
||||
EditorGUIUtility.PingObject(ni.asset);
|
||||
Selection.activeObject = ni.asset;
|
||||
}
|
||||
}) { text = "定位 SO 资产", style = { marginLeft = 10, marginRight = 10 } };
|
||||
_detailRoot.Add(pingBtn);
|
||||
|
||||
var copyBtn = new Button(() =>
|
||||
{
|
||||
EditorGUIUtility.systemCopyBuffer = ni.key;
|
||||
Debug.Log($"[LocalizationAudit] 已复制 Key:{ni.key}");
|
||||
}) { text = "复制 Key", style = { marginLeft = 10, marginRight = 10, marginTop = 4 } };
|
||||
_detailRoot.Add(copyBtn);
|
||||
}
|
||||
|
||||
private static void AddDetailRow(VisualElement parent, string label, string value)
|
||||
{
|
||||
var row = new VisualElement { style = { flexDirection = FlexDirection.Row, paddingLeft = 12, paddingTop = 2, paddingBottom = 2 } };
|
||||
row.Add(new Label(label + ":") { style = { width = 80, opacity = 0.6f, fontSize = 11 } });
|
||||
row.Add(new Label(value) { style = { flexGrow = 1, fontSize = 11 } });
|
||||
parent.Add(row);
|
||||
}
|
||||
|
||||
private static void PingTableFile(string language, string tableName)
|
||||
{
|
||||
string path = $"Assets/Resources/Localization/{language}/{tableName}.json";
|
||||
var asset = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
|
||||
if (asset != null)
|
||||
{
|
||||
EditorGUIUtility.PingObject(asset);
|
||||
Selection.activeObject = asset;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"[LocalizationAudit] 未找到表文件:{path}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b311cc7d8950e35458e44e0523e23ef0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,6 +6,7 @@ using UnityEngine.UIElements;
|
||||
using BaseGames.Dialogue;
|
||||
using BaseGames.Quest;
|
||||
using BaseGames.Editor.Shared;
|
||||
using BaseGames.Localization;
|
||||
|
||||
namespace BaseGames.Editor.Modules
|
||||
{
|
||||
@@ -70,8 +71,8 @@ namespace BaseGames.Editor.Modules
|
||||
};
|
||||
}
|
||||
|
||||
filterRow.Add(QuestModule.MakeFilterChip("有好感度", v => { filterAffinity = v; RebuildFilter(); }));
|
||||
filterRow.Add(QuestModule.MakeFilterChip("有头像", v => { filterPortrait = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("有好感度", v => { filterAffinity = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("有头像", v => { filterPortrait = v; RebuildFilter(); }));
|
||||
|
||||
container.Add(_listPane);
|
||||
_listPane.Refresh();
|
||||
@@ -114,7 +115,7 @@ namespace BaseGames.Editor.Modules
|
||||
|
||||
string nameDisplay = string.IsNullOrEmpty(n.nameKey)
|
||||
? "(未设置)"
|
||||
: (BaseGames.Localization.LocalizationManager.GetEditorPreview(n.nameKey, "Dialogue") ?? n.nameKey);
|
||||
: (BaseGames.Localization.LocalizationManager.GetEditorPreview(n.nameKey, LocalizationTable.Dialogue) ?? n.nameKey);
|
||||
SkillModule.AddChip(card, "名称", nameDisplay);
|
||||
if (!string.IsNullOrEmpty(n.nameKey))
|
||||
SkillModule.AddChip(card, "名称 Key", n.nameKey);
|
||||
@@ -263,7 +264,7 @@ namespace BaseGames.Editor.Modules
|
||||
string GetLoc(string key)
|
||||
{
|
||||
if (locCache.TryGetValue(key, out var v)) return v;
|
||||
v = BaseGames.Localization.LocalizationManager.GetEditorPreview(key, "Dialogue");
|
||||
v = BaseGames.Localization.LocalizationManager.GetEditorPreview(key, LocalizationTable.Dialogue);
|
||||
locCache[key] = v;
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using BaseGames.Quest;
|
||||
using BaseGames.Editor.Shared;
|
||||
using BaseGames.Localization;
|
||||
|
||||
namespace BaseGames.Editor.Modules
|
||||
{
|
||||
@@ -32,7 +33,7 @@ namespace BaseGames.Editor.Modules
|
||||
private System.Action<UnityEditor.PlayModeStateChange> _playModeHandler;
|
||||
|
||||
// 依赖关系图中 FindAll<QuestSO>() 的静态缓存,同一编辑器会话内复用,避免重复扫描磁盘
|
||||
private static QuestSO[] s_allQuestCache;
|
||||
private static List<QuestSO> s_allQuestCache;
|
||||
private static double s_allQuestCacheTime;
|
||||
private const double k_AllQuestCacheTtl = 5.0; // 秒;超时后下次打开 foldout 时刷新
|
||||
|
||||
@@ -96,62 +97,26 @@ namespace BaseGames.Editor.Modules
|
||||
};
|
||||
}
|
||||
|
||||
filterRow.Add(MakeFilterChip("主线", v => { filterCategory = v ? QuestCategory.Main : (QuestCategory?)null; RebuildFilter(); }));
|
||||
filterRow.Add(MakeFilterChip("支线", v => { filterCategory = v ? QuestCategory.Side : (QuestCategory?)null; RebuildFilter(); }));
|
||||
filterRow.Add(MakeFilterChip("日常", v => { filterCategory = v ? QuestCategory.Daily : (QuestCategory?)null; RebuildFilter(); }));
|
||||
filterRow.Add(MakeFilterChip("隐藏", v => { filterCategory = v ? QuestCategory.Hidden : (QuestCategory?)null; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("主线", v => { filterCategory = v ? QuestCategory.Main : (QuestCategory?)null; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("支线", v => { filterCategory = v ? QuestCategory.Side : (QuestCategory?)null; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("日常", v => { filterCategory = v ? QuestCategory.Daily : (QuestCategory?)null; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("隐藏", v => { filterCategory = v ? QuestCategory.Hidden : (QuestCategory?)null; RebuildFilter(); }));
|
||||
// 分隔
|
||||
var sep = new Label("|");
|
||||
sep.style.opacity = 0.3f;
|
||||
sep.style.marginLeft = 2;
|
||||
sep.style.marginRight = 2;
|
||||
filterRow.Add(sep);
|
||||
filterRow.Add(MakeFilterChip("有前置", v => { filterPrereq = v; RebuildFilter(); }));
|
||||
filterRow.Add(MakeFilterChip("无目标", v => { filterNoObj = v; RebuildFilter(); }));
|
||||
filterRow.Add(MakeFilterChip("可失败", v => { filterCanFail = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("有前置", v => { filterPrereq = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("无目标", v => { filterNoObj = v; RebuildFilter(); }));
|
||||
filterRow.Add(DataHubEditorKit.MakeFilterChip("可失败", v => { filterCanFail = v; RebuildFilter(); }));
|
||||
|
||||
container.Add(_listPane);
|
||||
_listPane.Refresh();
|
||||
}
|
||||
|
||||
internal static VisualElement MakeFilterChip(string label, System.Action<bool> onToggle)
|
||||
{
|
||||
bool active = false;
|
||||
var chip = new Label(label);
|
||||
chip.style.fontSize = 10;
|
||||
chip.style.paddingLeft = 6;
|
||||
chip.style.paddingRight = 6;
|
||||
chip.style.paddingTop = 2;
|
||||
chip.style.paddingBottom = 2;
|
||||
chip.style.marginRight = 4;
|
||||
chip.style.marginBottom = 2;
|
||||
chip.style.borderTopLeftRadius = 8;
|
||||
chip.style.borderTopRightRadius = 8;
|
||||
chip.style.borderBottomLeftRadius = 8;
|
||||
chip.style.borderBottomRightRadius = 8;
|
||||
chip.style.borderTopWidth = 1;
|
||||
chip.style.borderRightWidth = 1;
|
||||
chip.style.borderBottomWidth = 1;
|
||||
chip.style.borderLeftWidth = 1;
|
||||
chip.style.borderTopColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.4f));
|
||||
chip.style.borderRightColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.4f));
|
||||
chip.style.borderBottomColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.4f));
|
||||
chip.style.borderLeftColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.4f));
|
||||
chip.style.opacity = 0.6f;
|
||||
|
||||
void SetActive(bool on)
|
||||
{
|
||||
active = on;
|
||||
chip.style.opacity = on ? 1f : 0.6f;
|
||||
chip.style.backgroundColor = on
|
||||
? new StyleColor(new Color(0.3f, 0.6f, 1f, 0.25f))
|
||||
: StyleKeyword.None;
|
||||
onToggle(on);
|
||||
}
|
||||
|
||||
chip.RegisterCallback<ClickEvent>(_ => SetActive(!active));
|
||||
return chip;
|
||||
}
|
||||
=> DataHubEditorKit.MakeFilterChip(label, onToggle);
|
||||
|
||||
public void BuildDetailPane(VisualElement container, UnityEngine.Object selected)
|
||||
{
|
||||
@@ -201,7 +166,7 @@ namespace BaseGames.Editor.Modules
|
||||
}
|
||||
else
|
||||
{
|
||||
var resolved = BaseGames.Localization.LocalizationManager.GetEditorPreview(s.displayNameKey, "Quest");
|
||||
var resolved = BaseGames.Localization.LocalizationManager.GetEditorPreview(s.displayNameKey, LocalizationTable.Quest);
|
||||
nameDisplay = resolved != null ? resolved : s.displayNameKey + " ⚠ [缺少本地化]";
|
||||
}
|
||||
SkillModule.AddChip(card, "名称", nameDisplay);
|
||||
@@ -343,7 +308,7 @@ namespace BaseGames.Editor.Modules
|
||||
// 目标描述(本地化预览,灰色小字,显示策划填写的实际内容)
|
||||
if (!string.IsNullOrEmpty(obj.displayTextKey))
|
||||
{
|
||||
var resolved = BaseGames.Localization.LocalizationManager.GetEditorPreview(obj.displayTextKey, "Quest");
|
||||
var resolved = BaseGames.Localization.LocalizationManager.GetEditorPreview(obj.displayTextKey, LocalizationTable.Quest);
|
||||
bool l10nMissing = resolved == null;
|
||||
string descText = l10nMissing ? obj.displayTextKey + " ⚠ [缺少本地化]" : resolved;
|
||||
var desc = new Label(descText);
|
||||
|
||||
@@ -55,16 +55,19 @@ namespace BaseGames.Editor.Modules
|
||||
|
||||
if (_selected == null) return;
|
||||
|
||||
// Stats Card
|
||||
// Stats Card(复用 SkillModule 共享构建方法)
|
||||
var statsCard = BuildStatsCard(_selected);
|
||||
container.Add(statsCard);
|
||||
|
||||
// 操作按钮行
|
||||
var toolbar = BuildActionBar(_selected);
|
||||
container.Add(toolbar);
|
||||
// 操作按钮行(复用 BuildStandardActionBar,统一按钮样式)
|
||||
container.Add(SkillModule.BuildStandardActionBar<WeaponSO>(
|
||||
_selected, Folder, Prefix,
|
||||
created => _listPane.Refresh(created),
|
||||
cloned => _listPane.Refresh(cloned),
|
||||
() => _listPane.Refresh(null)));
|
||||
|
||||
// 分隔线
|
||||
container.Add(MakeDivider());
|
||||
container.Add(SkillModule.MakeDivider());
|
||||
|
||||
// Inspector
|
||||
var insp = new InspectorElement(_selected); container.Add(insp);
|
||||
@@ -92,92 +95,12 @@ namespace BaseGames.Editor.Modules
|
||||
|
||||
private static VisualElement BuildStatsCard(WeaponSO w)
|
||||
{
|
||||
var card = new VisualElement();
|
||||
card.style.flexDirection = FlexDirection.Row;
|
||||
card.style.flexWrap = Wrap.Wrap;
|
||||
card.style.paddingLeft = 12;
|
||||
card.style.paddingRight = 12;
|
||||
card.style.paddingTop = 8;
|
||||
card.style.paddingBottom = 8;
|
||||
card.style.marginBottom = 4;
|
||||
card.style.backgroundColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.08f));
|
||||
card.style.borderBottomWidth = 1;
|
||||
card.style.borderBottomColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.2f));
|
||||
|
||||
AddStatChip(card, "类型", w.weaponType.ToString());
|
||||
AddStatChip(card, "地面段数", (w.groundComboSteps?.Length ?? 0).ToString());
|
||||
AddStatChip(card, "空中段数", (w.airComboSteps?.Length ?? 0).ToString());
|
||||
AddStatChip(card, "ID", string.IsNullOrEmpty(w.weaponId) ? "-" : w.weaponId);
|
||||
var card = SkillModule.MakeCard();
|
||||
SkillModule.AddChip(card, "类型", w.weaponType.ToString());
|
||||
SkillModule.AddChip(card, "地面段数", (w.groundComboSteps?.Length ?? 0).ToString());
|
||||
SkillModule.AddChip(card, "空中段数", (w.airComboSteps?.Length ?? 0).ToString());
|
||||
SkillModule.AddChip(card, "ID", string.IsNullOrEmpty(w.weaponId) ? "-" : w.weaponId);
|
||||
return card;
|
||||
}
|
||||
|
||||
private static void AddStatChip(VisualElement parent, string label, string value)
|
||||
{
|
||||
var chip = new VisualElement();
|
||||
chip.style.flexDirection = FlexDirection.Row;
|
||||
chip.style.alignItems = Align.Center;
|
||||
chip.style.marginRight = 14;
|
||||
chip.style.marginBottom = 2;
|
||||
|
||||
var lbl = new Label(label + ":");
|
||||
lbl.style.opacity = 0.6f;
|
||||
lbl.style.fontSize = 11;
|
||||
lbl.style.marginRight = 3;
|
||||
chip.Add(lbl);
|
||||
|
||||
var val = new Label(value);
|
||||
val.style.fontSize = 11;
|
||||
val.style.unityFontStyleAndWeight = UnityEngine.FontStyle.Bold;
|
||||
chip.Add(val);
|
||||
|
||||
parent.Add(chip);
|
||||
}
|
||||
|
||||
private VisualElement BuildActionBar(WeaponSO w)
|
||||
{
|
||||
var bar = new VisualElement();
|
||||
bar.style.flexDirection = FlexDirection.Row;
|
||||
bar.style.paddingLeft = 12;
|
||||
bar.style.paddingRight = 12;
|
||||
bar.style.paddingTop = 6;
|
||||
bar.style.paddingBottom = 6;
|
||||
bar.style.flexWrap = Wrap.Wrap;
|
||||
|
||||
var btnPing = new Button(() => { EditorGUIUtility.PingObject(w); Selection.activeObject = w; })
|
||||
{ text = "在 Project 中定位", tooltip = "在 Project 窗口高亮此资产" };
|
||||
bar.Add(btnPing);
|
||||
|
||||
var btnClone = new Button(() =>
|
||||
{
|
||||
var clone = AssetOperations.Clone(w, Folder);
|
||||
if (clone != null) _listPane.Refresh(clone);
|
||||
}) { text = "克隆..." };
|
||||
bar.Add(btnClone);
|
||||
|
||||
var btnDel = new Button(() =>
|
||||
{
|
||||
if (AssetOperations.Delete(w)) _listPane.Refresh(null);
|
||||
}) { text = "删除" };
|
||||
btnDel.style.borderLeftColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
||||
btnDel.style.borderRightColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
||||
btnDel.style.borderTopColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
||||
btnDel.style.borderBottomColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
||||
btnDel.style.borderLeftWidth = 1;
|
||||
btnDel.style.borderRightWidth = 1;
|
||||
btnDel.style.borderTopWidth = 1;
|
||||
btnDel.style.borderBottomWidth = 1;
|
||||
btnDel.style.marginLeft = 8;
|
||||
bar.Add(btnDel);
|
||||
|
||||
return bar;
|
||||
}
|
||||
|
||||
private static VisualElement MakeDivider()
|
||||
{
|
||||
var d = new VisualElement();
|
||||
d.style.height = 1;
|
||||
d.style.backgroundColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.2f));
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user