using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using BaseGames.Editor.Modules;
namespace BaseGames.Editor
{
///
/// 数据管理总枢纽窗口(DataHub)。
/// 布局:导航侧边栏(120px) | TwoPaneSplitView → 列表区(220px) + 详情区(flex)。
/// 菜单:BaseGames / Data Hub (priority=50)
///
public class DataHubWindow : EditorWindow
{
private const string UssPath = "Assets/_Game/Scripts/Editor/UIToolkit/Editor.uss";
private const string PrefKey = "DataHub.ActiveModuleId";
private const float NavWidth = 120f;
private const float ListWidth = 220f;
private const float MinWinWidth = 680f;
private const float MinWinHeight = 420f;
[MenuItem("BaseGames/Data Hub", priority = 50)]
public static void Open()
{
var wnd = GetWindow();
wnd.titleContent = new GUIContent("Data Hub", EditorGUIUtility.IconContent("d_ScriptableObject Icon").image);
wnd.minSize = new Vector2(MinWinWidth, MinWinHeight);
}
// ── 状态 ─────────────────────────────────────────────────────────────
private readonly List _modules = new();
private readonly HashSet _initializedIds = new();
private IDataModule _activeModule;
private VisualElement _navSidebar;
// NavBar 搜索:按 DisplayName 过滤可见模块
private string _navFilter = "";
private readonly Dictionary _navButtons = new();
// 缓存:列表区和详情区引用(由 TwoPaneSplitView 子节点提供)
private VisualElement _listWrapper;
private VisualElement _detailWrapper;
// 当前选中资产
private UnityEngine.Object _selected;
// ── 生命周期 ──────────────────────────────────────────────────────────
public void CreateGUI()
{
// USS
var uss = AssetDatabase.LoadAssetAtPath(UssPath);
if (uss != null) rootVisualElement.styleSheets.Add(uss);
// 注册模块
RegisterModules();
// 构建 UI
BuildLayout();
// 恢复上次激活的模块
string savedId = EditorPrefs.GetString(PrefKey, string.Empty);
var toActivate = _modules.Find(m => m.ModuleId == savedId) ?? _modules.FirstOrDefault();
if (toActivate != null) ActivateModule(toActivate);
}
// ── 模块注册 ──────────────────────────────────────────────────────────
private void RegisterModules()
{
_modules.Clear();
// 自动发现所有实现 IDataModule 的非抽象类型(排除接口/抽象类本身)
// TypeCache 仅在 UnityEditor 中可用,零运行时开销
var moduleTypes = UnityEditor.TypeCache.GetTypesDerivedFrom();
var instances = new List(moduleTypes.Count);
foreach (var t in moduleTypes)
{
if (t.IsAbstract || t.IsInterface) continue;
try { instances.Add((IDataModule)Activator.CreateInstance(t)); }
catch (Exception ex)
{
Debug.LogWarning($"[DataHubWindow] 无法实例化模块 {t.Name}: {ex.Message}");
}
}
// 按 DisplayOrder 升序排列(若模块实现了 IDataModuleOrdered 则使用其值,否则默认 0)
instances.Sort((a, b) =>
{
int oa = a is IDataModuleOrdered ao ? ao.DisplayOrder : 0;
int ob = b is IDataModuleOrdered bo ? bo.DisplayOrder : 0;
int c = oa.CompareTo(ob);
return c != 0 ? c : string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase);
});
_modules.AddRange(instances);
}
// ── 布局 ─────────────────────────────────────────────────────────────
private void BuildLayout()
{
var root = rootVisualElement;
root.style.flexDirection = FlexDirection.Row;
root.style.flexGrow = 1;
// 导航侧边栏
_navSidebar = BuildNavSidebar();
root.Add(_navSidebar);
// 垂直分隔线
var divider = new VisualElement();
divider.style.width = 1;
divider.style.backgroundColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.25f));
root.Add(divider);
// TwoPaneSplitView(列表 + 详情)
var split = new TwoPaneSplitView(0, ListWidth, TwoPaneSplitViewOrientation.Horizontal);
split.style.flexGrow = 1;
root.Add(split);
// 列表区容器
_listWrapper = new VisualElement();
_listWrapper.style.flexGrow = 1;
_listWrapper.style.overflow = Overflow.Hidden;
split.Add(_listWrapper);
// 详情区:外层 ScrollView 提供滚动视口,_detailWrapper 是内容容器(自然高度)
var detailScroll = new ScrollView(ScrollViewMode.Vertical);
detailScroll.style.flexGrow = 1;
detailScroll.style.overflow = Overflow.Hidden;
split.Add(detailScroll);
_detailWrapper = new VisualElement();
_detailWrapper.style.flexDirection = FlexDirection.Column;
_detailWrapper.style.paddingBottom = 16;
detailScroll.Add(_detailWrapper);
}
private VisualElement BuildNavSidebar()
{
var sidebar = new VisualElement();
sidebar.style.width = NavWidth;
sidebar.style.flexShrink = 0;
sidebar.style.flexDirection = FlexDirection.Column;
sidebar.style.paddingTop = 8;
// 标题
var title = new Label("DATA HUB");
title.style.fontSize = 10;
title.style.opacity = 0.5f;
title.style.paddingLeft = 10;
title.style.marginBottom = 4;
title.style.unityFontStyleAndWeight = FontStyle.Bold;
sidebar.Add(title);
// 搜索框
var searchField = new TextField();
searchField.style.marginLeft = 6;
searchField.style.marginRight = 6;
searchField.style.marginBottom = 6;
searchField.tooltip = "按模块名称过滤";
// 自定义占位符效果
if (string.IsNullOrEmpty(searchField.value))
searchField.value = "";
searchField.RegisterValueChangedCallback(evt =>
{
_navFilter = evt.newValue ?? "";
ApplyNavFilter();
});
sidebar.Add(searchField);
_navButtons.Clear();
foreach (var module in _modules)
{
var btn = BuildNavItem(module);
_navButtons[module.ModuleId] = btn;
sidebar.Add(btn);
}
// 弹性填充
var spacer = new VisualElement();
spacer.style.flexGrow = 1;
sidebar.Add(spacer);
return sidebar;
}
private void ApplyNavFilter()
{
foreach (var module in _modules)
{
if (!_navButtons.TryGetValue(module.ModuleId, out var btn)) continue;
bool visible = string.IsNullOrEmpty(_navFilter) ||
module.DisplayName.IndexOf(_navFilter, System.StringComparison.OrdinalIgnoreCase) >= 0 ||
module.ModuleId.IndexOf(_navFilter, System.StringComparison.OrdinalIgnoreCase) >= 0;
btn.style.display = visible ? DisplayStyle.Flex : DisplayStyle.None;
}
}
private Button BuildNavItem(IDataModule module)
{
var btn = new Button(() => ActivateModule(module));
btn.name = "nav-" + module.ModuleId;
btn.style.flexDirection = FlexDirection.Row;
btn.style.alignItems = Align.Center;
btn.style.paddingLeft = 10;
btn.style.paddingRight = 8;
btn.style.paddingTop = 8;
btn.style.paddingBottom = 8;
btn.style.borderTopLeftRadius = 0;
btn.style.borderTopRightRadius = 0;
btn.style.borderBottomLeftRadius = 0;
btn.style.borderBottomRightRadius = 0;
btn.style.borderLeftWidth = 0;
btn.style.borderRightWidth = 0;
btn.style.borderTopWidth = 0;
btn.style.borderBottomWidth = 0;
btn.style.backgroundColor = new StyleColor(Color.clear);
btn.style.marginBottom = 2;
// 图标(容错:图标名无效时跳过,不报错)
if (!string.IsNullOrEmpty(module.IconName))
{
var content = EditorGUIUtility.IconContent(module.IconName);
if (content?.image != null)
{
var icon = new Image { image = content.image };
icon.style.width = 16;
icon.style.height = 16;
icon.style.marginRight = 6;
btn.Add(icon);
}
}
var label = new Label(module.DisplayName);
label.style.flexGrow = 1;
btn.Add(label);
return btn;
}
// ── 模块切换 ──────────────────────────────────────────────────────────
private void ActivateModule(IDataModule module)
{
if (_activeModule == module) return;
_activeModule = module;
_selected = null;
// 更新导航项视觉状态
foreach (var m in _modules)
{
var navBtn = _navSidebar.Q