From 2d030a97dab6d4a8d945814302ccf38f68b81b9f Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Mon, 6 Apr 2026 16:20:46 +0800 Subject: [PATCH] feat(xcui): advance core and editor validation flow --- docs/plan/XCUI完整架构设计与执行计划.md | 1571 +++++++++++++++++ .../XCEngine/UI/Runtime/UIScreenTypes.h | 13 + .../XCEngine/UI/Style/DocumentStyleCompiler.h | 33 + .../src/UI/Runtime/UIScreenDocumentHost.cpp | 318 +++- engine/src/UI/Style/DocumentStyleCompiler.cpp | 598 +++++++ engine/src/UI/Style/StyleResolver.cpp | 42 +- new_editor/CMakeLists.txt | 3 + .../Editor/UIEditorPanelRegistry.h | 52 + .../Editor/UIEditorWorkspaceController.h | 111 ++ .../Editor/UIEditorWorkspaceModel.h | 2 + .../Editor/UIEditorWorkspaceSession.h | 94 + new_editor/src/Host/Application.cpp | 23 +- new_editor/src/editor/EditorShellAsset.cpp | 93 + new_editor/src/editor/EditorShellAsset.h | 28 + .../src/editor/UIEditorPanelRegistry.cpp | 74 + .../editor/UIEditorWorkspaceController.cpp | 357 ++++ .../src/editor/UIEditorWorkspaceModel.cpp | 28 + .../src/editor/UIEditorWorkspaceSession.cpp | 476 +++++ new_editor/ui/themes/editor_shell.xctheme | 23 +- new_editor/ui/views/editor_shell.xcui | 5 +- tests/UI/Core/CMakeLists.txt | 2 +- tests/UI/Core/integration/CMakeLists.txt | 14 +- tests/UI/Core/integration/README.md | 26 +- .../UI/Core/integration/input/CMakeLists.txt | 12 + tests/UI/Core/integration/input/README.md | 8 + .../input/keyboard_focus/CMakeLists.txt | 35 + .../input/keyboard_focus/README.md | 15 + .../input/keyboard_focus/View.xcui | 10 +- .../input/keyboard_focus}/main.cpp | 4 +- .../input/pointer_states/CMakeLists.txt | 35 + .../input/pointer_states/README.md | 14 + .../input/pointer_states/View.xcui | 8 +- .../input/pointer_states}/main.cpp | 4 +- .../input/scroll_view/CMakeLists.txt | 35 + .../integration/input/scroll_view/View.xcui | 6 +- .../input/scroll_view/captures/.gitkeep | 0 .../integration/input/scroll_view}/main.cpp | 4 +- .../input/shortcut_scope/CMakeLists.txt | 35 + .../input/shortcut_scope/View.xcui | 8 +- .../integration/input/shortcut_scope/main.cpp | 8 + .../UI/Core/integration/layout/CMakeLists.txt | 10 + .../layout/splitter_resize/CMakeLists.txt | 35 + .../layout/splitter_resize/View.xcui | 4 +- .../layout/splitter_resize/main.cpp | 8 + .../layout/tab_strip_selection/CMakeLists.txt | 35 + .../layout/tab_strip_selection/View.xcui | 8 +- .../tab_strip_selection/captures/.gitkeep | 0 .../layout/tab_strip_selection/main.cpp | 8 + .../layout/workspace_compose/CMakeLists.txt | 35 + .../layout/workspace_compose/View.xcui | 6 +- .../workspace_compose/captures/.gitkeep | 0 .../layout/workspace_compose/main.cpp | 8 + .../UI/Core/integration/shared/CMakeLists.txt | 61 + .../integration/shared/src/Application.cpp | 802 +++++++++ .../Core/integration/shared/src/Application.h | 83 + .../integration/shared/src/AutoScreenshot.cpp | 165 ++ .../integration/shared/src/AutoScreenshot.h | 52 + .../shared/src/CoreValidationScenario.cpp | 130 ++ .../shared/src/CoreValidationScenario.h | 26 + .../shared/src/InputModifierTracker.h | 173 ++ .../integration/shared/src/NativeRenderer.cpp | 485 +++++ .../integration/shared/src/NativeRenderer.h | 65 + .../shared/themes/core_validation.xctheme | 65 + .../UI/Core/integration/style/CMakeLists.txt | 6 + .../style/theme_tokens/CMakeLists.txt | 35 + .../integration/style/theme_tokens/View.xcui | 50 + .../style/theme_tokens/captures/.gitkeep | 1 + .../integration/style/theme_tokens/main.cpp | 8 + tests/UI/Core/integration/text/CMakeLists.txt | 6 + .../text/utf8_focus_surface/CMakeLists.txt | 35 + .../text/utf8_focus_surface/View.xcui | 43 + .../text/utf8_focus_surface/captures/.gitkeep | 1 + .../text/utf8_focus_surface/main.cpp | 8 + tests/UI/Core/unit/CMakeLists.txt | 27 +- .../unit/test_core_validation_registry.cpp | 78 + .../Core/unit/test_input_modifier_tracker.cpp | 90 + tests/UI/Core/unit/test_layout_engine.cpp | 130 ++ tests/UI/Core/unit/test_ui_core.cpp | 240 +++ .../UI/Core/unit/test_ui_expansion_model.cpp | 45 + .../unit/test_ui_flat_hierarchy_helpers.cpp | 145 ++ .../UI/Core/unit/test_ui_input_dispatcher.cpp | 146 ++ .../test_ui_keyboard_navigation_model.cpp | 101 ++ .../Core/unit/test_ui_property_edit_model.cpp | 80 + .../UI/Core/unit/test_ui_selection_model.cpp | 42 + tests/UI/Core/unit/test_ui_style_system.cpp | 341 ++++ tests/UI/Core/unit/test_ui_text_editing.cpp | 59 + .../unit/test_ui_text_input_controller.cpp | 287 +++ tests/UI/Editor/CMakeLists.txt | 1 - tests/UI/Editor/integration/CMakeLists.txt | 11 +- tests/UI/Editor/integration/README.md | 57 +- .../Editor/integration/input/CMakeLists.txt | 12 - tests/UI/Editor/integration/input/README.md | 9 - .../input/keyboard_focus/CMakeLists.txt | 35 - .../input/keyboard_focus/README.md | 18 - .../input/pointer_states/CMakeLists.txt | 35 - .../input/pointer_states/README.md | 17 - .../input/scroll_view/CMakeLists.txt | 35 - .../input/shortcut_scope/CMakeLists.txt | 35 - .../Editor/integration/layout/CMakeLists.txt | 10 - .../layout/splitter_resize/CMakeLists.txt | 35 - .../layout/splitter_resize/main.cpp | 8 - .../layout/tab_strip_selection/CMakeLists.txt | 35 - .../layout/tab_strip_selection/main.cpp | 8 - .../layout/workspace_compose/CMakeLists.txt | 35 - .../layout/workspace_compose/main.cpp | 8 - .../Editor/integration/shared/CMakeLists.txt | 9 +- .../integration/shared/src/Application.cpp | 128 +- .../integration/shared/src/Application.h | 3 +- .../shared/src/EditorValidationScenario.cpp | 70 +- .../shared/src/EditorValidationScenario.h | 3 +- .../shared/themes/editor_validation.xctheme | 19 +- .../Editor/integration/state/CMakeLists.txt | 1 + .../state/panel_session_flow/CMakeLists.txt | 29 + .../panel_session_flow/captures/.gitkeep | 1 + .../state/panel_session_flow/main.cpp | 648 +++++++ .../workspace_shell_compose/CMakeLists.txt | 35 + .../workspace_shell_compose/View.xcui | 94 + .../workspace_shell_compose/captures/.gitkeep | 1 + .../main.cpp | 2 +- tests/UI/Editor/unit/CMakeLists.txt | 13 +- .../test_editor_shell_asset_validation.cpp | 53 + .../unit/test_editor_validation_registry.cpp | 66 - .../test_ui_editor_collection_primitives.cpp | 84 + .../unit/test_ui_editor_panel_chrome.cpp | 126 ++ .../unit/test_ui_editor_panel_registry.cpp | 49 + .../test_ui_editor_workspace_controller.cpp | 148 ++ .../unit/test_ui_editor_workspace_session.cpp | 183 ++ tests/UI/TEST_SPEC.md | 70 +- 128 files changed, 9961 insertions(+), 773 deletions(-) create mode 100644 docs/plan/XCUI完整架构设计与执行计划.md create mode 100644 engine/include/XCEngine/UI/Style/DocumentStyleCompiler.h create mode 100644 engine/src/UI/Style/DocumentStyleCompiler.cpp create mode 100644 new_editor/include/XCNewEditor/Editor/UIEditorPanelRegistry.h create mode 100644 new_editor/include/XCNewEditor/Editor/UIEditorWorkspaceController.h create mode 100644 new_editor/include/XCNewEditor/Editor/UIEditorWorkspaceSession.h create mode 100644 new_editor/src/editor/UIEditorPanelRegistry.cpp create mode 100644 new_editor/src/editor/UIEditorWorkspaceController.cpp create mode 100644 new_editor/src/editor/UIEditorWorkspaceSession.cpp create mode 100644 tests/UI/Core/integration/input/CMakeLists.txt create mode 100644 tests/UI/Core/integration/input/README.md create mode 100644 tests/UI/Core/integration/input/keyboard_focus/CMakeLists.txt create mode 100644 tests/UI/Core/integration/input/keyboard_focus/README.md rename tests/UI/{Editor => Core}/integration/input/keyboard_focus/View.xcui (79%) rename tests/UI/{Editor/integration/input/shortcut_scope => Core/integration/input/keyboard_focus}/main.cpp (57%) create mode 100644 tests/UI/Core/integration/input/pointer_states/CMakeLists.txt create mode 100644 tests/UI/Core/integration/input/pointer_states/README.md rename tests/UI/{Editor => Core}/integration/input/pointer_states/View.xcui (82%) rename tests/UI/{Editor/integration/input/keyboard_focus => Core/integration/input/pointer_states}/main.cpp (57%) create mode 100644 tests/UI/Core/integration/input/scroll_view/CMakeLists.txt rename tests/UI/{Editor => Core}/integration/input/scroll_view/View.xcui (95%) rename tests/UI/{Editor => Core}/integration/input/scroll_view/captures/.gitkeep (100%) rename tests/UI/{Editor/integration/input/pointer_states => Core/integration/input/scroll_view}/main.cpp (57%) create mode 100644 tests/UI/Core/integration/input/shortcut_scope/CMakeLists.txt rename tests/UI/{Editor => Core}/integration/input/shortcut_scope/View.xcui (91%) create mode 100644 tests/UI/Core/integration/input/shortcut_scope/main.cpp create mode 100644 tests/UI/Core/integration/layout/CMakeLists.txt create mode 100644 tests/UI/Core/integration/layout/splitter_resize/CMakeLists.txt rename tests/UI/{Editor => Core}/integration/layout/splitter_resize/View.xcui (93%) create mode 100644 tests/UI/Core/integration/layout/splitter_resize/main.cpp create mode 100644 tests/UI/Core/integration/layout/tab_strip_selection/CMakeLists.txt rename tests/UI/{Editor => Core}/integration/layout/tab_strip_selection/View.xcui (90%) rename tests/UI/{Editor => Core}/integration/layout/tab_strip_selection/captures/.gitkeep (100%) create mode 100644 tests/UI/Core/integration/layout/tab_strip_selection/main.cpp create mode 100644 tests/UI/Core/integration/layout/workspace_compose/CMakeLists.txt rename tests/UI/{Editor => Core}/integration/layout/workspace_compose/View.xcui (94%) rename tests/UI/{Editor => Core}/integration/layout/workspace_compose/captures/.gitkeep (100%) create mode 100644 tests/UI/Core/integration/layout/workspace_compose/main.cpp create mode 100644 tests/UI/Core/integration/shared/CMakeLists.txt create mode 100644 tests/UI/Core/integration/shared/src/Application.cpp create mode 100644 tests/UI/Core/integration/shared/src/Application.h create mode 100644 tests/UI/Core/integration/shared/src/AutoScreenshot.cpp create mode 100644 tests/UI/Core/integration/shared/src/AutoScreenshot.h create mode 100644 tests/UI/Core/integration/shared/src/CoreValidationScenario.cpp create mode 100644 tests/UI/Core/integration/shared/src/CoreValidationScenario.h create mode 100644 tests/UI/Core/integration/shared/src/InputModifierTracker.h create mode 100644 tests/UI/Core/integration/shared/src/NativeRenderer.cpp create mode 100644 tests/UI/Core/integration/shared/src/NativeRenderer.h create mode 100644 tests/UI/Core/integration/shared/themes/core_validation.xctheme create mode 100644 tests/UI/Core/integration/style/CMakeLists.txt create mode 100644 tests/UI/Core/integration/style/theme_tokens/CMakeLists.txt create mode 100644 tests/UI/Core/integration/style/theme_tokens/View.xcui create mode 100644 tests/UI/Core/integration/style/theme_tokens/captures/.gitkeep create mode 100644 tests/UI/Core/integration/style/theme_tokens/main.cpp create mode 100644 tests/UI/Core/integration/text/CMakeLists.txt create mode 100644 tests/UI/Core/integration/text/utf8_focus_surface/CMakeLists.txt create mode 100644 tests/UI/Core/integration/text/utf8_focus_surface/View.xcui create mode 100644 tests/UI/Core/integration/text/utf8_focus_surface/captures/.gitkeep create mode 100644 tests/UI/Core/integration/text/utf8_focus_surface/main.cpp create mode 100644 tests/UI/Core/unit/test_core_validation_registry.cpp create mode 100644 tests/UI/Core/unit/test_input_modifier_tracker.cpp create mode 100644 tests/UI/Core/unit/test_layout_engine.cpp create mode 100644 tests/UI/Core/unit/test_ui_core.cpp create mode 100644 tests/UI/Core/unit/test_ui_expansion_model.cpp create mode 100644 tests/UI/Core/unit/test_ui_flat_hierarchy_helpers.cpp create mode 100644 tests/UI/Core/unit/test_ui_input_dispatcher.cpp create mode 100644 tests/UI/Core/unit/test_ui_keyboard_navigation_model.cpp create mode 100644 tests/UI/Core/unit/test_ui_property_edit_model.cpp create mode 100644 tests/UI/Core/unit/test_ui_selection_model.cpp create mode 100644 tests/UI/Core/unit/test_ui_style_system.cpp create mode 100644 tests/UI/Core/unit/test_ui_text_editing.cpp create mode 100644 tests/UI/Core/unit/test_ui_text_input_controller.cpp delete mode 100644 tests/UI/Editor/integration/input/CMakeLists.txt delete mode 100644 tests/UI/Editor/integration/input/README.md delete mode 100644 tests/UI/Editor/integration/input/keyboard_focus/CMakeLists.txt delete mode 100644 tests/UI/Editor/integration/input/keyboard_focus/README.md delete mode 100644 tests/UI/Editor/integration/input/pointer_states/CMakeLists.txt delete mode 100644 tests/UI/Editor/integration/input/pointer_states/README.md delete mode 100644 tests/UI/Editor/integration/input/scroll_view/CMakeLists.txt delete mode 100644 tests/UI/Editor/integration/input/shortcut_scope/CMakeLists.txt delete mode 100644 tests/UI/Editor/integration/layout/CMakeLists.txt delete mode 100644 tests/UI/Editor/integration/layout/splitter_resize/CMakeLists.txt delete mode 100644 tests/UI/Editor/integration/layout/splitter_resize/main.cpp delete mode 100644 tests/UI/Editor/integration/layout/tab_strip_selection/CMakeLists.txt delete mode 100644 tests/UI/Editor/integration/layout/tab_strip_selection/main.cpp delete mode 100644 tests/UI/Editor/integration/layout/workspace_compose/CMakeLists.txt delete mode 100644 tests/UI/Editor/integration/layout/workspace_compose/main.cpp create mode 100644 tests/UI/Editor/integration/state/CMakeLists.txt create mode 100644 tests/UI/Editor/integration/state/panel_session_flow/CMakeLists.txt create mode 100644 tests/UI/Editor/integration/state/panel_session_flow/captures/.gitkeep create mode 100644 tests/UI/Editor/integration/state/panel_session_flow/main.cpp create mode 100644 tests/UI/Editor/integration/workspace_shell_compose/CMakeLists.txt create mode 100644 tests/UI/Editor/integration/workspace_shell_compose/View.xcui create mode 100644 tests/UI/Editor/integration/workspace_shell_compose/captures/.gitkeep rename tests/UI/Editor/integration/{input/scroll_view => workspace_shell_compose}/main.cpp (82%) create mode 100644 tests/UI/Editor/unit/test_editor_shell_asset_validation.cpp delete mode 100644 tests/UI/Editor/unit/test_editor_validation_registry.cpp create mode 100644 tests/UI/Editor/unit/test_ui_editor_collection_primitives.cpp create mode 100644 tests/UI/Editor/unit/test_ui_editor_panel_chrome.cpp create mode 100644 tests/UI/Editor/unit/test_ui_editor_panel_registry.cpp create mode 100644 tests/UI/Editor/unit/test_ui_editor_workspace_controller.cpp create mode 100644 tests/UI/Editor/unit/test_ui_editor_workspace_session.cpp diff --git a/docs/plan/XCUI完整架构设计与执行计划.md b/docs/plan/XCUI完整架构设计与执行计划.md new file mode 100644 index 00000000..87b21747 --- /dev/null +++ b/docs/plan/XCUI完整架构设计与执行计划.md @@ -0,0 +1,1571 @@ +# XCUI完整架构设计与执行计划 + +## 1. 文档定位 + +本文档定义 `XCUI` 的完整目标、分层架构、核心数据模型、运行机制、编辑器集成方式、迁移策略与执行计划。 + +`XCUI` 的定位不是“再做一个游戏内 UI 模块”,而是: + +- XCEngine 的统一 UI 平台 +- Editor 与 Runtime 共用的一套 UI Core +- 面向 AI Coding Agent 友好的 UI 开发体系 +- 未来替代当前 editor 中 ImGui 主路径的正式方案 + +本文档默认服务于两个目标: + +- 给后续实现提供明确蓝图 +- 给 AI / 人类开发者提供稳定的架构边界 + +--- + +## 2. 背景与问题定义 + +当前 XCEngine 的 editor 已经形成了较清晰的主链: + +- `RHI -> Rendering -> Editor Viewport -> AssetDatabase/Library -> Mono Scripting` + +但 UI 层目前仍以 ImGui 即时模式为主,存在以下问题: + +- 过程式 UI 代码体量大,面板文件容易膨胀 +- 状态、布局、事件、业务逻辑容易缠绕在一起 +- AI 不擅长稳定修改大段 imperative native UI 代码 +- 现有 UI 逻辑难以沉淀为资源化、组件化、可热重载的体系 +- editor UI 和未来 runtime UI 之间没有统一技术底座 + +### 2.1 当前问题不是“有没有 UI”,而是“UI 的组织方式不适合 AI” + +当前 editor 已经有大量真实能力: + +- Hierarchy +- Project +- Inspector +- Console +- Scene/Game Viewport +- Play Mode / Scripting / Asset 工作流 + +因此,XCUI 的目标不是重做 editor 后端能力,而是重做 UI 前端组织方式。 + +### 2.2 为什么不能直接照抄 Unity UI + +不采用 Unity 风格 UI 的主要原因: + +- `RectTransform / Anchor / Pivot / Canvas` 模型复杂度高 +- 组件化表达不够直接 +- inspector/custom editor 体系过重 +- 对 AI 来说,状态流和布局意图不够清晰 +- editor UI 与 runtime UI 分裂严重 + +### 2.3 为什么也不直接采用浏览器/WebView路线 + +本文档明确不采用“真正 HTML/CSS/JS + 浏览器内核”作为主路线,原因如下: + +- 这会把问题从 UI 架构转移成浏览器宿主工程 +- 会引入大量与引擎无关的复杂性 +- 不利于 editor/runtime 共享同一套 native UI Core +- 会让 viewport、输入、宿主生命周期复杂化 + +XCUI 借鉴前端范式,但不引入浏览器运行时。 + +--- + +## 3. XCUI的总体目标 + +### 3.1 核心目标 + +XCUI 必须同时满足以下目标: + +1. AI 能稳定理解、生成、修改 UI +2. Editor 与 Runtime 共用统一 UI Core +3. UI 可资源化、可热重载、可调试 +4. 复杂度显著低于 Unity UI +5. 能逐步替代 editor 当前的 ImGui 主路径 +6. 能承载 editor 级别的面板、布局、属性表单、树控件和 viewport 壳层 + +### 3.2 非目标 + +XCUI 明确不做以下事情: + +- 不做浏览器 +- 不做 DOM +- 不做完整 CSS cascade +- 不复刻 Unity UGUI / UI Toolkit +- 不把普通 UI 节点做成 Scene GameObject +- 不在 V1 做完整 world-space UI 体系 + +### 3.3 成功标准 + +XCUI 成功的标志不是“能画几个按钮”,而是: + +- editor 核心公共边界中不再暴露 ImGui 类型 +- Inspector / Project / Console / Hierarchy 至少 4 个核心面板迁移到 XCUI +- Scene/Game 使用 `ViewportSlot` 承载视口纹理和输入边界 +- `.xcui/.xctheme/.xcschema` 支持热重载 +- runtime HUD/menu 可以基于同一套 UI Core 构建 +- editor 最终可不依赖 ImGui 运行主 UI + +--- + +## 4. 总体架构 + +### 4.1 分层结构 + +XCUI 采用如下四层架构: + +```text +Editor / Runtime Application + | + v +XCUI Views / ViewModels / Commands + | + v +XCUI Core +(State / Binding / Layout / Style / Input / Render / Widgets) + | + v +Backend +(ImGui Adapter -> 过渡期) +(Native RHI Renderer -> 最终目标) +``` + +### 4.2 在仓库中的推荐目录 + +```text +engine/ + include/XCEngine/UI/ + Core/ + State/ + Binding/ + Layout/ + Style/ + Input/ + Render/ + Text/ + Widgets/ + Markup/ + Schema/ + Runtime/ + DevTools/ + src/UI/ + +editor/ + src/XCUIHost/ + src/XCUIViewModels/ + src/XCUIAdapters/ + src/XCUICommands/ + ui/views/ + ui/themes/ + ui/schemas/ + +project/ + Assets/UI/ + Assets/Themes/ + Assets/Schemas/ + +tests/ + UI/ +``` +### 4.2.1 当前执行覆盖规则(2026-04-06) + +以下规则在当前阶段覆盖本节中所有与目录落点有关的模糊表述: + +- `editor/` 当前视为 ImGui 版本冻结区;在 XCUI editor shell 成熟前,不直接在该目录中推进替换开发。 +- 新的 `Editor` 层实现当前先落在 `new_editor/`,用于 editor shell、editor-only widget 与工作区壳层构建。 +- `tests/UI` 继续只承担 XCUI 的 `unit / integration` 验证职责,不承载正式 editor 实现。 +- `engine/UI` 当前继续只放 `Core / Runtime / shared` 部分,不再继续沉积 editor-only 代码。 +- 当 `new_editor/` 中的 XCUI editor shell 达到替换条件后,再计划性回收进正式 `editor/`。 + +#### 当前过渡期目录(自 2026-04-06 起执行) +```text +engine/ + include/XCEngine/UI/ + src/UI/ + # 只承载 Core / Runtime / shared UI 基础层 + +new_editor/ + src/ + ui/ + captures/ + # 当前新的 Editor 层与 editor shell 先在这里构建 + +editor/ + # 当前 ImGui 版本冻结,不作为本阶段 XCUI 主实现目录 + +tests/ + UI/ + # XCUI 验证体系入口,不承载正式 editor 实现 +``` + +### 4.3 模块划分 + +| 模块 | 职责 | +|---|---| +| `UI/Core` | UI 树、节点生命周期、失效传播、实例管理 | +| `UI/State` | 响应式状态、派生状态、store | +| `UI/Binding` | 数据绑定、命令绑定、viewmodel 适配 | +| `UI/Layout` | 测量、布局、容器规则 | +| `UI/Style` | 样式、主题 token、状态样式 | +| `UI/Input` | 指针、键盘、焦点、拖拽、快捷键 | +| `UI/Render` | draw list、渲染命令、后端抽象 | +| `UI/Text` | 字体、文本测量、IME、换行 | +| `UI/Widgets` | 基础控件和复合控件 | +| `UI/Markup` | `.xcui` 解析、编译、热重载 | +| `UI/Schema` | inspector/form schema | +| `UI/Runtime` | runtime screen/player/系统接入 | +| `UI/DevTools` | UI 树、layout、style、binding 调试工具 | + +--- + +## 5. 核心设计原则 + +### 5.1 Retained-mode,而不是即时模式 + +XCUI 的正式形态是 retained-mode: + +- UI 树长期存在 +- 状态变化驱动局部更新 +- 布局与绘制是独立阶段 +- 不以“每帧手写过程式调用”作为主路径 + +### 5.2 声明式优先,代码式保底 + +XCUI 应同时支持: + +- `Markup-first` +- `Code-first` + +但主路径必须是 `Markup-first`,原因如下: + +- 树状 UI 更适合 AI 生成和修改 +- 结构、样式、行为边界更清晰 +- 更适合热重载和资源化 + +### 5.3 单向数据流 + +强制采用: + +- `State -> View` +- `UI Event -> Command -> Domain -> State Update -> View Refresh` + +禁止: + +- Widget 直接到处改业务对象 +- UI 节点绕过命令系统随意操作 `SceneManager` +- 控件内部偷偷维护大量业务状态 + +### 5.4 Viewport 是宿主,不是普通控件 + +`Scene/Game Viewport` 必须视为特殊宿主节点: + +- 它承载纹理 +- 它定义输入边界 +- 它连接 viewport 服务 +- 它不负责普通 UI 布局逻辑之外的 gizmo/picking/世界 overlay + +### 5.5 Schema 优先于硬编码 Inspector + +对于 Inspector、Material、ImportSettings、Script 字段: + +- 默认走 schema + auto form +- 只有少量复杂控件才走 custom section + +目标是让“新增/修改一个属性面板”更多是改 schema 和 view,而不是继续写大块 imperative C++。 + +--- + +## 6. 编程模型 + +### 6.1 View / ViewModel / Command + +#### View + +职责: + +- 描述结构 +- 描述布局 +- 描述样式 +- 建立绑定 +- 发出命令意图 + +不负责: + +- 直接修改业务对象 +- 直接处理 domain 规则 + +#### ViewModel + +职责: + +- 订阅 editor/runtime 的 domain state +- 整理成 UI 可绑定状态 +- 组织派生状态 +- 绑定命令和事件 + +#### Command + +职责: + +- 把 UI 意图翻译成稳定的业务命令 +- editor 命令落到现有 `Commands::*` +- runtime 命令落到游戏 UI action handler + +### 6.2 推荐命令命名 + +```text +Editor.Entity.Create +Editor.Entity.Delete +Editor.Entity.Rename +Editor.Project.Open +Editor.Project.Refresh +Editor.Scripting.Rebuild +Editor.Layout.Reset +Runtime.Menu.Open +Runtime.Menu.Close +Runtime.HUD.Toggle +``` + +### 6.3 绑定表达式约束 + +XCUI 不引入完整脚本表达式引擎。 + +Markup 中支持的表达式范围只建议包括: + +- `bind` +- `if` +- `not` +- `equals` +- `foreach` +- `command` + +这能保证: + +- AI 易于生成 +- 编译器易于诊断 +- runtime 复杂度可控 + +--- + +## 7. 文件格式设计 + +### 7.1 `.xcui` + +用于描述 UI 视图树。 + +示例: + +```xml + + + + + +