using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace BaseGames.Editor.Modules
{
///
/// 批量验证结果窗口:以可滚动列表展示各项配置问题,
/// 每条记录附带"选中"按钮,点击后高亮并选中对应资产(EditorGUIUtility.PingObject)。
/// 支持 Error/Warning Tab 切换与文本搜索过滤。
/// 由各验证模块(QuestModule、DialogueModule、NpcModule)在检测到问题时弹出。
///
internal class QuestValidationResultWindow : EditorWindow
{
internal struct Issue
{
public string message;
public bool isError;
public UnityEngine.Object asset; // null = 无对应资产(如孤儿触发器)
}
private List _issues;
private int _errorCount;
private int _warnCount;
private int _totalItems;
private string _itemLabel = "资产";
private Vector2 _scroll;
// ── 过滤状态 ─────────────────────────────────────────────────────────
private enum TabMode { All, ErrorsOnly, WarnsOnly }
private TabMode _tab = TabMode.All;
private string _filter = "";
private static readonly GUIStyle s_tabActive = null; // 延迟初始化
private static readonly GUIStyle s_tabInactive = null;
// ── 打开入口 ──────────────────────────────────────────────────────────
internal static void Show(List issues, int errorCount, int warnCount, int totalItems, string windowTitle = "批量验证结果", string itemLabel = "资产")
{
var win = GetWindow(true, windowTitle, true);
win._issues = issues;
win._errorCount = errorCount;
win._warnCount = warnCount;
win._totalItems = totalItems;
win._itemLabel = itemLabel;
win._tab = TabMode.All;
win._filter = "";
win.minSize = new Vector2(560, 380);
win.Show();
}
// ── 绘制 ──────────────────────────────────────────────────────────────
private void OnGUI()
{
if (_issues == null) { EditorGUILayout.LabelField("无数据。"); return; }
bool clean = _errorCount == 0 && _warnCount == 0;
// ── 标题摘要 ──
EditorGUILayout.Space(6);
var summaryStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 12 };
if (clean) summaryStyle.normal.textColor = new Color(0.2f, 0.75f, 0.2f);
string prefix = clean ? "✅ " : (_errorCount > 0 ? "❌ " : "⚠ ");
string summary = $"{prefix}验证完成:{_totalItems} 个{_itemLabel} · {_errorCount} 个错误 · {_warnCount} 个警告";
EditorGUILayout.LabelField(summary, summaryStyle);
EditorGUILayout.Space(4);
if (clean)
{
EditorGUILayout.LabelField($"所有 {_itemLabel} 配置均合法!", EditorStyles.centeredGreyMiniLabel);
return;
}
// ── 分隔线 ──
var divRect = EditorGUILayout.GetControlRect(false, 1);
EditorGUI.DrawRect(divRect, new Color(0.35f, 0.35f, 0.35f));
EditorGUILayout.Space(4);
// ── Tab 切换 + 搜索框 ──
EditorGUILayout.BeginHorizontal();
DrawTab("全部", TabMode.All, _issues.Count);
DrawTab("错误", TabMode.ErrorsOnly, _errorCount);
DrawTab("警告", TabMode.WarnsOnly, _warnCount);
GUILayout.FlexibleSpace();
GUILayout.Label("🔍", GUILayout.Width(18));
_filter = EditorGUILayout.TextField(_filter, GUILayout.Width(180));
if (GUILayout.Button("×", GUILayout.Width(22))) _filter = "";
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(4);
// ── 问题列表 ──
_scroll = EditorGUILayout.BeginScrollView(_scroll);
int shown = 0;
foreach (var issue in _issues)
{
if (!MatchesFilter(issue)) continue;
shown++;
DrawIssueRow(issue);
EditorGUILayout.Space(2);
}
if (shown == 0)
EditorGUILayout.LabelField("(当前过滤条件下无结果)", EditorStyles.centeredGreyMiniLabel);
EditorGUILayout.EndScrollView();
// ── 底部状态栏 ──
EditorGUILayout.Space(2);
var statusRect = EditorGUILayout.GetControlRect(false, 1);
EditorGUI.DrawRect(statusRect, new Color(0.3f, 0.3f, 0.3f));
EditorGUILayout.LabelField(
$"显示 {shown} / {_issues.Count} 条",
EditorStyles.centeredGreyMiniLabel);
}
// ── 辅助方法 ─────────────────────────────────────────────────────────
private bool MatchesFilter(Issue issue)
{
if (_tab == TabMode.ErrorsOnly && !issue.isError) return false;
if (_tab == TabMode.WarnsOnly && issue.isError) return false;
if (!string.IsNullOrEmpty(_filter))
{
bool msgMatch = issue.message.Contains(_filter, System.StringComparison.OrdinalIgnoreCase);
bool assetMatch = issue.asset != null &&
issue.asset.name.Contains(_filter, System.StringComparison.OrdinalIgnoreCase);
if (!msgMatch && !assetMatch) return false;
}
return true;
}
private void DrawTab(string label, TabMode mode, int count)
{
bool active = _tab == mode;
var style = active
? new GUIStyle(EditorStyles.miniButtonMid) { fontStyle = FontStyle.Bold }
: EditorStyles.miniButtonMid;
if (active) style.normal.textColor = new Color(0.4f, 0.8f, 1f);
string text = $"{label} ({count})";
if (GUILayout.Button(text, style, GUILayout.MinWidth(72)))
_tab = mode;
}
private static void DrawIssueRow(Issue issue)
{
EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);
// 图标
var iconContent = issue.isError
? EditorGUIUtility.IconContent("console.erroricon.sml")
: EditorGUIUtility.IconContent("console.warnicon.sml");
GUILayout.Label(iconContent, GUILayout.Width(20), GUILayout.Height(18));
// 消息文字
EditorGUILayout.LabelField(issue.message, EditorStyles.wordWrappedLabel);
// 定位按钮(有资产引用时显示)
if (issue.asset != null)
{
if (GUILayout.Button("选中", GUILayout.Width(40), GUILayout.Height(18)))
{
EditorGUIUtility.PingObject(issue.asset);
Selection.activeObject = issue.asset;
}
}
EditorGUILayout.EndHorizontal();
}
}
}