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; // 缓存:列表区和详情区引用(由 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(); _modules.Add(new WeaponModule()); _modules.Add(new SkillModule()); _modules.Add(new EnemyModule()); _modules.Add(new FormModule()); _modules.Add(new BossSkillModule()); _modules.Add(new CharmModule()); _modules.Add(new StreamingModule()); _modules.Add(new DialogueModule()); _modules.Add(new QuestModule()); _modules.Add(new ActorModule()); } // ── 布局 ───────────────────────────────────────────────────────────── 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 = 6; title.style.unityFontStyleAndWeight = FontStyle.Bold; sidebar.Add(title); foreach (var module in _modules) { var btn = BuildNavItem(module); sidebar.Add(btn); } // 弹性填充 var spacer = new VisualElement(); spacer.style.flexGrow = 1; sidebar.Add(spacer); return sidebar; } 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