diff --git a/AGENT.md b/AGENT.md index bbc3a8f9..47fe5875 100644 --- a/AGENT.md +++ b/AGENT.md @@ -57,10 +57,10 @@ ## 2. 当前工程事实 -- 顶层 `CMakeLists.txt` 当前纳入 `engine/`、`editor/`、`new_editor/`、`managed/`、`mvs/RenderDoc/` 和 `tests/`。 -- `engine/` 构建静态库 `XCEngine`;`editor/` 构建 `XCEditor`,但输出文件名仍是 `editor/bin//XCEngine.exe`。 +- 顶层 `CMakeLists.txt` 当前纳入 `engine/`、`editor/`、`managed/`、`mvs/RenderDoc/` 和 `tests/`。 +- `engine/` 构建静态库 `XCEngine`;`editor/` 构建 `XCUIEditor` 静态库和 `XCEditor` 可执行目标。 - `editor/` 目前继续保留为当前正式编辑器、行为对照和视觉基线来源。 -- `new_editor/` 当前构建 `XCUIEditorLib`、`XCUIEditorHost`;启用 `XCENGINE_BUILD_XCUI_EDITOR_APP` 时会输出 `new_editor/bin//XCUIEditor.exe`,并被视为未来正式编辑器主线,而不再只是临时 sandbox。 +- 启用 `XCENGINE_BUILD_XCUI_EDITOR_APP` 时,`XCEditor` 输出 `build/editor//XCEngine.exe`。 - editor 默认把仓库内的 `project/` 识别为工程根目录,也支持 `--project ` 覆盖。 - 当前工程真实使用 `Assets/ + .meta + Library/` 的项目布局;`project/Library/` 是当前 workflow 的一部分,不是可随手忽略的垃圾目录。 - Mono 运行时与 editor 的脚本类发现都从 `/Library/ScriptAssemblies/` 加载程序集。 @@ -146,13 +146,12 @@ ### 3.4 XCUI / New Editor -- `new_editor/` 是未来正式编辑器主线,不再只是 sandbox;旧 `editor/` 当前继续保留为正式编辑器、行为对照和视觉基线。 +- `editor/` 是当前 XCUI 编辑器主线;不要再把 `new_editor/` 当成当前 checkout 的构建入口。 - 当前宿主分层是: - - `XCUIEditorLib` - - `XCUIEditorHost` - - `XCUIEditorApp`(可选应用壳) -- 共享 UI core、runtime screen host 与 widget 基础能力主要沉淀在 `engine/include/XCEngine/UI/` 与 `engine/src/UI/`;`new_editor/` 负责 XCUI editor 壳、宿主与产品装配。 -- `tests/UI/` 是当前 XCUI `Core / Editor / Runtime` 三层的唯一正式基础层验证入口;`new_editor/` 不承担测试堆场职责。 + - `XCUIEditor` + - `XCEditor`(可选应用壳,输出 `XCEngine.exe`) +- 共享 UI core、runtime screen host 与 widget 基础能力主要沉淀在 `engine/include/XCEngine/UI/` 与 `engine/src/UI/`;`editor/` 负责 XCUI editor 壳、宿主与产品装配。 +- `tests/UI/` 是当前 XCUI `Core / Editor / Runtime` 三层的唯一正式基础层验证入口;`editor/` 不承担测试堆场职责。 ### 3.5 Scripting @@ -294,7 +293,7 @@ python -B docs/api/_tools/audit_api_docs.py 当前审计口径已经同时覆盖: - `engine/include/XCEngine/**` -- `new_editor/include/XCEditor/**` +- `editor/include/XCEditor/**` - `editor/src/**` ## 5. 推荐构建与验证入口 @@ -346,7 +345,7 @@ ctest --test-dir build -C Debug --output-on-failure - 资源导入与工程布局:`engine/include/XCEngine/Core/Asset/`、`engine/src/Core/Asset/`、`editor/src/Managers/ProjectManager.cpp`、`project/Assets/`、`project/Library/` - Material / shader / artifact:`engine/include/XCEngine/Resources/Material/`、`engine/src/Resources/Material/`、`engine/include/XCEngine/Core/Asset/ArtifactFormats.h`、`tests/Resources/Material/` - Editor viewport / gizmo / picking:`editor/src/Viewport/`、`editor/src/panels/SceneViewPanel.cpp`、`tests/Editor/` -- XCUI / new_editor:`engine/include/XCEngine/UI/`、`engine/src/UI/`、`new_editor/include/XCEditor/`、`new_editor/src/`、`tests/UI/` +- XCUI / editor:`engine/include/XCEngine/UI/`、`engine/src/UI/`、`editor/include/XCEditor/`、`editor/src/`、`editor/app/`、`tests/UI/` - Editor actions / project routing:`editor/src/Actions/`、`editor/src/Commands/`、`editor/src/Core/`、`editor/src/Managers/`、`tests/Editor/test_action_routing.cpp` - 脚本运行时与程序集:`engine/include/XCEngine/Scripting/`、`engine/src/Scripting/`、`managed/`、`project/Assets/Scripts/`、`tests/Scripting/` - API 文档:`docs/api/main.md`、`docs/api/XCEngine/`、`docs/api/XCEditor/`、`docs/api/_guides/`、`docs/api/_tools/audit_api_docs.py`、`docs/plan/API文档目录*.md`、`docs/used/API文档实时同步任务池_2026-04-03.md` diff --git a/README.md b/README.md index c9133d99..b17bbf4d 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ - `UIScreenPlayer` - `UISystem` - `tests/UI/` 是当前 XCUI `Core / Editor / Runtime` 三层的正式基础层验证入口 -- `new_editor/` 是未来正式编辑器主线,不再只是临时沙盒;当前已经包含树视图、列表视图、菜单、标签条、属性网格、字段控件、workspace / dock / viewport shell 等基础组件 +- `editor/` 是当前 XCUI 编辑器主线;当前已经包含树视图、列表视图、菜单、标签条、属性网格、字段控件、workspace / dock / viewport shell 等基础组件 ### 音频 @@ -127,7 +127,7 @@ - 当前 `RHI` 后端为 `D3D12`、`OpenGL`、`Vulkan` - 当前项目资产工作流已经接入 `AssetDatabase + Artifact + Library` - 当前 `Mono C#` 脚本程序集与运行时链路已经接入 -- 当前 `XCUI` 新编辑器路线以 `new_editor/` 为正式主线继续推进 +- 当前 `XCUI` 编辑器路线以 `editor/` 为正式主线继续推进 ## 快速开始 @@ -160,7 +160,7 @@ cmake --build build --config Debug --target XCEditor 运行: ```powershell -.\editor\bin\Debug\XCEngine.exe +.\build\editor\Debug\XCEngine.exe ``` 如需构建项目脚本程序集: @@ -172,13 +172,13 @@ cmake --build build --config Debug --target xcengine_project_managed_assemblies 如需构建 XCUI 新编辑器宿主: ```powershell -cmake --build build --config Debug --target XCUIEditorApp +cmake --build build --config Debug --target XCEditor ``` 运行 XCUI 新编辑器宿主: ```powershell -.\new_editor\bin\Debug\XCUIEditor.exe +.\build\editor\Debug\XCEngine.exe ``` ## 测试入口 @@ -260,41 +260,28 @@ XCEngine/ | |- blueprint-skill.md | `- blueprint.md |- editor/ +| |- AGENTS.md | |- CMakeLists.txt -| |- README.md +| |- app/ +| | |- Bootstrap/ +| | |- Commands/ +| | |- Composition/ +| | |- Features/ +| | |- Platform/ +| | |- Project/ +| | |- Rendering/ +| | |- Scene/ +| | |- State/ +| | |- System/ +| | |- UtilityWindows/ +| | |- Windowing/ +| | `- main.cpp | |- bin/ +| |- include/ +| | `- XCEditor/ | |- resources/ | | `- Icons/ | `- src/ -| |- Actions/ -| |- Commands/ -| |- ComponentEditors/ -| |- Core/ -| |- Layers/ -| |- Layout/ -| |- Managers/ -| |- panels/ -| |- Platform/ -| |- Scripting/ -| |- UI/ -| |- Utils/ -| |- Viewport/ -| | |- Passes/ -| | |- SceneViewportChrome.* -| | |- SceneViewportInteractionFrame.h -| | |- SceneViewportNavigation.h -| | |- SceneViewportOverlayBuilder.* -| | |- SceneViewportOverlayFrameCache.* -| | |- SceneViewportOverlaySpriteResources.* -| | |- SceneViewportPassSpecs.h -| | |- SceneViewportPicker.* -| | |- SceneViewportResourcePaths.h -| | |- SceneViewportTransformGizmoCoordinator.* -| | `- ViewportHostService.h -| |- Application.cpp -| |- Application.h -| |- Theme.cpp -| `- main.cpp |- engine/ | |- CMakeLists.txt | |- include/ @@ -345,30 +332,6 @@ XCEngine/ | |- RenderDoc/ | |- ui/ | `- VolumeRenderer/ -|- new_editor/ -| |- app/ -| | |- Host/ -| | |- Application.cpp -| | |- Application.h -| | `- main.cpp -| |- bin/ -| |- include/ -| | `- XCEditor/ -| | |- Collections/ -| | |- Fields/ -| | |- Foundation/ -| | |- Shell/ -| | `- Widgets/ -| |- src/ -| | |- Collections/ -| | |- Fields/ -| | |- Foundation/ -| | |- Shell/ -| | `- Widgets/ -| |- ui/ -| | |- themes/ -| | `- views/ -| `- CMakeLists.txt |- project/ | |- .xceditor/ | | |- imgui_layout.ini diff --git a/editor/AGENTS.md b/editor/AGENTS.md index f603b141..2cccfe0b 100644 --- a/editor/AGENTS.md +++ b/editor/AGENTS.md @@ -1,508 +1,323 @@ # XCUI Editor Agent Guide -This file documents the mandatory editor architecture for agents working under -`editor/`. It is an architecture contract, not just a description of whatever -the current checkout happens to contain. - -If this file conflicts with `editor/CMakeLists.txt` or the real directory tree, -the target-shape rules in this file win. Fix the code or CMake to match these -rules unless the user explicitly asks to change the architecture contract. +This file is a working map for agents changing `editor/`. It is not a +substitute for reading the code. If this guide conflicts with the current +implementation, trust the implementation and update this guide in the same +change. ## Build Shape -The important production targets are: +- The root `CMakeLists.txt` always adds `editor/` before `tests/`. +- `editor/CMakeLists.txt` always builds `XCUIEditor`, a static library made + from `editor/include/XCEditor/**` plus `editor/src/**`. +- `XCUIEditor` outputs `XCUIEditor.lib` and is the reusable, platform-neutral + editor UI layer. It links + against `XCEngine` and is covered mainly by `tests/UI/Editor/unit`. +- `XCEditor` is built when `XCENGINE_BUILD_XCUI_EDITOR_APP=ON`; that mode + requires `XCENGINE_ENABLE_RENDERING_EDITOR_SUPPORT=ON`. The executable target + is named `XCEditor`, but its output name is `XCEngine`. +- The app target owns Win32 hosting, D3D12 window rendering, project/scene + runtime wiring, real editor panels, utility windows, and screenshots. +- The app is intentionally packaged as one executable target. Do not restore + internal app split targets such as `XCUIEditorAppLib`, `XCUIEditorAppCore`, + or `XCUIEditorHost` unless the product architecture is explicitly changed. +- Keep the CMake target named `XCEditor` so it does not collide with the engine + library target named `XCEngine`; keep the built executable output name as + `XCEngine`. +- Shared code uses C++20 and MSVC `/utf-8`; keep new files ASCII unless the + surrounding file already uses another encoding for a real reason. -- `XCUIEditorLib`: reusable XCEditor framework code from `editor/src` and - `editor/include/XCEditor`, including the reusable window authority, - synchronization planner, and presentation projection under - `XCEditor/Windowing`. -- `XCUIEditorApp`: concrete editor executable. Its output name is `XCEngine`. +## Directory Map -`XCUIEditorLib` is the only production static library allowed under -`editor/`. All app-side code under `editor/app`, including `Windowing`, -`Platform`, `Rendering`, `Composition`, `Features`, and `UtilityWindows`, must -compile into `XCUIEditorApp` unless the code belongs in `XCUIEditorLib`. - -Do not create, restore, or keep app-internal static library targets. Names such -as `XCUIEditorAppWindowing`, `XCUIEditorAppCore`, `XCUIEditorAppLib`, and -`XCUIEditorHost` are forbidden production target boundaries. If any of these -targets exist in CMake, treat them as stale build debt and remove them as part -of the boundary cleanup. - -There is now a narrow public `editor/include/XCEditor/Windowing` layer for the -generic window authority model, synchronization plan/planner, and presentation -projection. App-specific window orchestration remains under -`editor/app/Windowing`, render host contracts remain under -`editor/app/Rendering/Host`, the concrete D3D12 renderer remains under -`editor/app/Rendering/D3D12`, and the concrete Win32 host remains under -`editor/app/Platform/Win32`. +- `include/XCEditor/` is the public editor UI API: collections, docking, + fields, foundation, menus, panels, shell, viewport, widgets, windowing, and + workspace. +- `src/` implements that public API and may include private `src/**/Internal.h` + helpers. It should stay independent of app, Win32, D3D12, and project + runtime concerns. +- `app/Bootstrap/` contains process startup and shutdown through + `Application`. +- `app/Composition/` builds the editor shell asset, coordinates shell update + phases, and connects app state to hosted panel runtimes. +- `app/Windowing/` owns window instances, content controllers, frame transfer + requests, lifecycle, workspace synchronization, and utility-window creation. +- `app/Platform/Win32/` owns `HWND`, message dispatch, native pointer capture, + borderless chrome, DPI, placement, and Win32 system integration. +- `app/Rendering/` owns editor-window rendering hosts, D3D12 UI rendering, + built-in icons, viewport render targets, object picking, and scene viewport + passes. +- `app/Features/` contains user-facing panels and editor tools: Hierarchy, + Scene viewport, Inspector, Project, Console, Color Picker, and component UI. +- `app/Project/`, `app/Scene/`, and `app/State/` hold application services that + panels should use instead of owning global state themselves. ## Layering -Use these ownership boundaries when changing code: - -- `editor/include/XCEditor` and `editor/src`: reusable editor framework. - Keep this layer independent from app state, Win32, D3D12 host code, and - `App::*` types. -- `editor/include/XCEditor/Windowing` and `editor/src/Windowing`: reusable - window authority, validation, synchronization planning, commit, and - presentation projection. Keep this layer generic and free of app content, - host runtime, native platform, and rendering details. -- `editor/app/Composition`, `Commands`, `Features`, `Project`, `Scene`, - `State`, `System`, `UtilityWindows`: editor product semantics. -- `editor/app/Windowing/Content`, `Coordinator`, `Frame`, `Host`, `Runtime`: - app window orchestration, content ownership, host-facing content binding - contracts, frame driving, frame transfer, and per-window runtime state. Keep - this layer backend-neutral; it may depend on `editor/app/Rendering/Host` - contracts, but not concrete render backends. -- `editor/app/Platform/Win32`: native window, message dispatch, input, - lifecycle, chrome, HWND ownership, Win32 diagnostics, concrete native render - surface adapters, and native host adapter behavior. -- `editor/app/Rendering/Host`: app rendering contracts consumed by app - windowing and app content, including the render-runtime factory interface. -- `editor/app/Rendering/D3D12`: concrete D3D12 window renderer, UI renderer, - texture host, text system, render loop, render-runtime adapter, and - render-runtime factory. - -The semantic dependency direction should remain: - -```text -XCEditor framework - <- editor app semantics - <- app windowing runtime / rendering host contracts - <- application composition root / concrete Win32 and rendering adapters -``` +- Keep `XCUIEditor` below the app. Public headers under `include/XCEditor` + must not include `app/**`, Win32, D3D12, or feature-panel headers. +- Keep platform specifics in `app/Platform/Win32`; keep GPU-window specifics in + `app/Rendering/D3D12`. +- Keep shell composition and widget logic data-driven. The reusable layer should + emit frames, layouts, draw data, command results, and transfer requests; the + app decides how those requests affect native windows and engine services. +- Use existing controller types for mutation: + `UIEditorWorkspaceController`, `UIEditorWindowWorkspaceController`, and + `EditorWindowSystem`. +- Use the existing service objects for app state: `EditorContext`, + `EditorProjectRuntime`, `EditorSceneRuntime`, `EditorSelectionService`, + `EditorCommandFocusService`, and utility-window request state. ## Startup Flow -The application starts through: - -```text -app/main.cpp - -> RunXCUIEditorApp - -> Application::Run - -> Application::Initialize -``` - -The primary workspace window is initialized through: - -```text -EditorContext::BuildWorkspaceController() - -> EditorWindowSystem::BootstrapPrimaryWindow(...) - -> EditorWindowManager::CreateWorkspaceWindow(...) - -> EditorWindowContentFactory::CreateWorkspaceContentController(...) - -> EditorWindowRenderRuntimeFactory::CreateWindowRenderRuntime() - -> EditorWindowRuntimeController(EditorContext, contentController, renderRuntime) - -> EditorWindowInstance(runtimeController) - -> EditorWindowHostRuntime::CreateHostWindow(windowInstance, ...) - -> Win32 EditorWindow native peer -``` - -Keep authoritative window bootstrap in `EditorWindowSystem`; do not move it -back into the Win32 host. +1. `app/main.cpp` enters `RunXCEditor`, which creates `Application`. +2. `Application::Initialize` resolves the repo root, enables DPI awareness, + initializes runtime tracing under the executable `logs/` directory, and + installs the unhandled-exception crash trace hook. +3. `EditorContext::Initialize` builds and validates the shell asset, initializes + project and scene runtimes, resets selection/focus/tool state, builds + command and shortcut services, and marks the shell ready. +4. `Application` registers the Win32 window class, creates the Win32 system + interaction host, bootstraps `EditorWindowSystem` with the primary + workspace state, creates `EditorWindowHostRuntime`, creates the D3D12 render + runtime factory, and constructs `EditorWindowManager`. +5. `EditorWindowManager::CreateWorkspaceWindow` creates an + `EditorWindowInstance`, attaches an `EditorWorkspaceWindowContentController`, + asks the host runtime to create the native window, and initializes the + per-window render/content runtime. +6. The main loop drains up to 64 Win32 messages per tick, updates async + resource loads, reaps destroyed windows, renders all running windows, and + honors smoke-test auto-exit settings. +7. `Application::WndProc` forwards registered windows to + `EditorWindowMessageDispatcher`; unknown messages fall back to + `DefWindowProcW`. ## Frame Runtime Ownership -`EditorWindowManager` owns steady-state frame iteration and the immediate-frame -callbacks used by native paint, resize, maximize/restore, and chrome actions. -The Win32 host may request a frame through `EditorWindowHostCoordinator`, but it -must not own the editor frame loop or fetch `EditorContext`. - -`EditorWindowRuntimeController` lives under `editor/app/Windowing/Runtime`. -App windowing creates it from `EditorContext` plus a workspace or utility -content controller plus a backend-neutral `EditorWindowRenderRuntime`, then -wraps it in app-owned `EditorWindowInstance`. The Win32 host receives the -instance only as an `EditorHostWindow` owner/native-peer binding; it must not -store or call `EditorWindowRuntimeController` directly, create content -controllers, or receive `EditorContext`. - -Concrete renderer selection is composed above both app windowing and the native -host. `Application` creates the current -`D3D12EditorWindowRenderRuntimeFactory` and passes it into -`EditorWindowManager`; app windowing asks the factory for backend-neutral -`Rendering::Host::EditorWindowRenderRuntime` instances. `EditorWindowInstance` -owns runtime controllers that already contain their render runtime; the Win32 -host must not create concrete render backends or own render runtimes. -`EditorWindowRuntimeController` may call -`EditorWindowRenderRuntime`, `UiTextureHost`, and `ViewportRenderHost`, but it -must not include `Rendering/D3D12` headers, `windows.h`, or HWND types. - -The host contract direction is: - -```text -EditorWindowManager / coordinators - -> ask EditorWindowRenderRuntimeFactory for EditorWindowRenderRuntime - -> create EditorWindowRuntimeController - -> wrap it in app-owned EditorWindowInstance - -> EditorWindowHostRuntime::CreateHostWindow(windowInstance, ...) - -> Win32 EditorWindow owns HWND/input/chrome and supplies native snapshots - -> EditorWindowInstance renders from snapshots and returns native frame commands -``` - -The native peer contract for frame/runtime data is data-shaped. Native render -surface creation crosses through `EditorNativeWindowRuntimeSurface`, which -carries an abstract `Rendering::Host::EditorWindowRenderRuntimeSurface` rather -than a raw HWND/`void*`; per-frame native facts cross through -`EditorNativeWindowFrameSnapshot`; frame-side native effects cross back through -`EditorNativeWindowFrameCommands`. Do not add one-off native-peer getters for -normal frame data such as HWND, render size, DPI, pending input, cursor point, -workspace bounds, title-bar mode, or cursor application. Extend the -snapshot/command structs when the frame contract needs new data. - -Host-visible content binding interfaces live under -`editor/app/Windowing/Host`, not `editor/app/Windowing/Content`. The native -host may consume small binding contracts such as -`EditorWindowInputFeedbackBinding`, `EditorWindowTitleBarBinding`, and -`EditorWindowDockHostBinding`; it must not include the content-controller -header or couple to concrete workspace/utility content controllers. +- `EditorContext` owns the app-level shell asset, editor session, command + routing, selection/focus services, project runtime, scene runtime, color + picker state, and pending utility-window requests. +- `EditorWindowSystem` owns the authoritative + `UIEditorWindowWorkspaceSet`. Workspace windows should derive their local + projection from this state rather than storing independent layout truth. +- `EditorWorkspaceWindowContentController` asks `EditorWindowSystem` for a live + `UIEditorWorkspaceController` every frame. A live controller writes mutations + through to the authoritative window workspace state; a copied controller is + only a preview. +- `EditorShellRuntime` owns per-window interactive runtime state: viewport host + service, built-in icons, hosted panels, scene viewport feature, shell + interaction state/frame, splitter correction state, trace entries, draw + composer, interaction engine, hosted panel coordinator, and session + coordinator. +- `EditorWindowRuntimeController` owns the content controller, render runtime, + screenshot controller, title-bar logo texture, text measurer access, DPI + scale, and frame-rate display. +- `EditorWindowInstance` is the managed host-window object. It owns lifecycle + state and bridges its native peer to the runtime controller. +- `EditorWindow` in `app/Platform/Win32/Windowing` owns the native peer + behavior: `HWND`, queued input, pointer capture, chrome interaction, resize + snapshots, cursor feedback, invalidation, and native destruction. ## Window Authority Model -`EditorWindowSystem` owns the authoritative `UIEditorWindowWorkspaceSet` through -`EditorWindowWorkspaceStore`. - -Normal per-frame workspace edits now use direct writes into that authoritative -state: - -```text -EditorWorkspaceWindowContentController::UpdateAndAppend(...) - -> EditorWindowSystem::TryBuildLiveWindowWorkspaceController(windowId, ...) - -> UIEditorWorkspaceController::BindToState(...) - -> workspace operations mutate the bound authoritative workspace/session -``` - -The old normal path is obsolete: - -```text -snapshot diff - -> workspaceMutation frame request - -> coordinator - -> synchronization plan - -> commit -``` - -Do not reintroduce `workspaceMutation` as the steady-state route for ordinary -layout, tab, visibility, or active-panel edits inside an existing workspace -window. - -Cross-window create, update, close, and destroyed-window reconciliation still -use the planner/coordinator flow: - -```text -target UIEditorWindowWorkspaceSet - -> EditorWindowSystem::BuildPlanForWindowSet(...) - -> EditorWindowWorkspaceCoordinator::ApplySynchronizationPlan(...) - -> EditorWindowSystem::CommitSynchronizationPlan(...) -``` - -`EditorWindowWorkspaceCoordinator::RefreshWindowPresentation(...)` refreshes -each workspace window projection from authoritative state. Presentation should -follow authority; it should not become a second source of truth. +- The authoritative window/workspace state is the + `UIEditorWindowWorkspaceSet` stored by `EditorWindowSystem`. +- Presentation data is derived from state through + `BuildEditorWorkspaceWindowProjection`; do not hand-maintain detached window + title, tab-strip title, primary flag, or minimum size in separate places. +- Workspace mutations that can affect multiple windows should start with + `EditorWindowSystem::BuildWorkspaceMutationController`, validate through + `ValidateWindowSet`, build a synchronization plan, apply host-window actions, + then commit the plan back to `EditorWindowSystem`. +- `EditorWindowSynchronizationPlanner` compares target workspace state against + host snapshots and emits create/update/close actions. Extend this planner and + its tests when changing workspace-window synchronization rules. +- Destroying the primary workspace window intentionally closes remaining + workspace windows. Destroying a detached workspace window reconciles the + authoritative window set and refreshes the remaining windows. +- `EditorWindowWorkspaceCoordinator::RefreshWindowPresentation` is the normal + path for refreshing projections and titles after a frame. ## Frame Transfer Requests -`EditorWindowFrameTransferRequests` is only for host-side or cross-window side -effects that cannot be represented as direct in-window workspace edits. +Frame transfer requests are the app boundary for work that cannot be committed +inside pure shell/widget code. -Current request fields are: - -- `workspace.beginGlobalTabDrag` -- `workspace.detachPanel` -- `utility.openUtilityWindow` - -There is no `workspace.workspaceMutation` field in the current frame transfer -contract. Treat any doc, comment, or test name that says otherwise as stale. +- `EditorWindowFrameOrchestrator` converts shell results into + `EditorWindowFrameTransferRequests`. +- Workspace requests currently include `beginGlobalTabDrag` and `detachPanel`. + These are consumed by `EditorWindowWorkspaceCoordinator`. +- Utility requests currently include `openUtilityWindow`. These are produced + from `EditorContext::RequestOpenUtilityWindow` and consumed by + `EditorUtilityWindowCoordinator`. +- Panels and shell code should request window-level work through transfer + requests or context request state, not by creating/destroying native windows + directly. +- Global tab drag uses screen coordinates, a captured owner window, an external + dock-host drop preview on the target window, and + `EditorWindowPointerCaptureOwner::GlobalTabDrag`. ## Window Categories -Workspace and utility windows share the native host path but use distinct -content controllers. +- Workspace windows use `EditorWorkspaceWindowContentController`. They expose + workspace, dock-host, input-feedback, title-bar, and viewport-rendering + capabilities. +- Detached workspace windows are still workspace windows. Their projection can + enable the detached title-bar tab strip and derive the window title from the + single visible panel. +- Utility windows use `EditorUtilityWindowContentController`. They host an + `EditorUtilityWindowPanel`, do not participate in workspace synchronization, + and currently do not expose dock-host or viewport capabilities. +- Utility descriptors live in `EditorUtilityWindowRegistry.cpp`. Current + utility windows are Color Picker and Add Component; both are single-instance + topmost tool windows. -- Workspace windows use `EditorWorkspaceWindowContentController`. -- Utility windows use `EditorUtilityWindowContentController`. -- App windowing creates content through `EditorWindowContentFactory`. -- App windowing wraps content in `EditorWindowRuntimeController`, then owns that - runtime through `EditorWindowInstance`. -- The concrete host creates a native peer for an existing app-owned - `EditorHostWindow`; it does not receive or validate runtime controllers. +## Shell, Panels, And Commands -Utility windows are descriptor driven through `EditorUtilityWindowDescriptor`, -`EditorUtilityWindowRegistry`, and `CreateEditorUtilityWindowPanel(...)`. -Register new utility windows there rather than hard-coding them in Win32 host -logic. Utility descriptors may express native host semantics such as -`EditorWindowNativeShellRole::ToolWindow`, but they must not include -`windows.h` or encode Win32 style constants such as `WS_EX_*` or `WS_*`. +- `EditorShellAssetBuilder.cpp` defines the product shell: panel registry, + default workspace layout, command registry, menus, toolbar buttons, shortcuts, + capture root, and status-bar definitions. +- Panel IDs are centralized in `EditorPanelIds.h`; prefer these constants over + raw string literals in app code. +- Hosted panels receive mounted bounds and filtered input through + `UIEditorHostedPanelDispatchFrame`. +- `EditorShellHostedPanelCoordinator` filters hosted-panel input when shell + capture owns the pointer stream, updates scene viewport state, wires app + services into panels, dispatches hosted panels, and syncs command focus. +- `EditorHostCommandBridge` routes host commands to focused edit routes, + project asset routes, scene routes, inspector routes, workspace commands, or + the app exit handler. +- `WorkspaceEventSync` is the current place where hierarchy/project frame + events update app status, selection-backed session state, scene-open requests, + and runtime trace entries. + +## Viewport Rendering + +- Scene and Game are `ViewportShell` presentations. The Scene panel is the + active editor viewport implementation; Game is registered as a viewport panel + but is not equivalent to the runtime game view yet. +- `SceneViewportFeature` owns `SceneViewportController` and + `SceneViewportRenderService`. +- `ViewportHostService` is the per-window manager for viewport requests, + render-target allocation, retirement, fallback clearing, and dispatch to the + attached `ViewportRenderHost`. +- `SceneViewportRenderService` renders scene content through the engine + renderer and owns object-id picking state. Keep editor picking/render support + behind `XCENGINE_ENABLE_RENDERING_EDITOR_SUPPORT`. +- D3D12 window rendering is behind the abstract + `Rendering::Host::EditorWindowRenderRuntime`; use the host interfaces when + adding app-level features. ## Modification Rules -- First decide whether the change belongs to XCEditor framework, app semantics, - app windowing, Win32 host, or rendering host. -- Keep public framework headers free of `App::*`, Win32, and D3D12 host types. -- Keep `editor/include/XCEditor` and `editor/src` free of `windows.h`, HWND, - Win32 exception types such as `_EXCEPTION_POINTERS`, and DbgHelp/StackWalk - code. Win32 crash stack capture belongs under `editor/app/Platform/Win32`; - framework trace code only writes platform-neutral trace records. -- Do not add `editor/app` as an include directory for `XCUIEditorLib`. - App-only services must cross into framework code through framework-owned - interfaces and app-side adapters. -- Do not compile `${XCUI_EDITOR_SHARED_SOURCES}` directly into `XCUIEditorApp`; - the executable should consume shared framework code through `XCUIEditorLib`. -- Do not add any app-internal static library targets under `editor/`. The only - editor static library target is `XCUIEditorLib`. -- Do not compile `editor/app/Windowing` as a standalone library target. It is an - app source ownership boundary only, and should compile into `XCUIEditorApp`. -- Use `editor/include/XCEditor/Windowing` and `editor/src/Windowing` for - generic window authority, synchronization, validation, and presentation - projection. -- Use `editor/app/Windowing` for app-specific window runtime semantics, - content, frame transfer, host contracts, host-visible content binding - interfaces, runtime controllers, and coordinators. -- Use `editor/app/Rendering/Host` for renderer-facing contracts that app - windowing or app content may consume, including - `EditorWindowRenderRuntimeFactory`. -- Use `editor/app/Rendering/D3D12` for concrete D3D12 renderer ownership, - swap-chain/present/capture details, UI texture/text/render systems, and the - D3D12 `EditorWindowRenderRuntime` implementation and factory. -- Use `editor/app/Platform/Win32` only for native host behavior and message - integration. Win32 code may request frames through the host coordinator; it - must not own the editor frame loop, expose `EditorContext`, or create - concrete render backends. It may create concrete Win32 render surface adapter - objects that implement `Rendering::Host::EditorWindowRenderRuntimeSurface`. -- Do not let `editor/app/Windowing` include `Platform/Win32` headers. -- Do not let `editor/app/Windowing` include `Rendering/D3D12` headers, - `windows.h`, or HWND types. It should consume concrete rendering only through - `Rendering::Host::EditorWindowRenderRuntime` and - `Rendering::Host::EditorWindowRenderRuntimeFactory`, and it must pass native - render surfaces only as abstract `EditorWindowRenderRuntimeSurface` objects. -- Do not let `editor/app/Platform/Win32` include `Rendering/D3D12` headers or - implement render-runtime factory methods on the native host interfaces. -- Do not let app semantics such as `UtilityWindows` encode Win32 style bits. - Use semantic host policy fields, and map those semantics to `WS_*` constants - inside the Win32 host. -- Do not spread D3D12 host types into app windowing content, coordinator, - frame-transfer, runtime-controller, or public host-contract headers. -- Do not let Win32 host code create workspace or utility content directly. - It should receive an app-owned `EditorHostWindow`/`EditorWindowInstance` - created by app windowing, not an `EditorWindowRuntimeController`. -- Do not let `editor/app/Platform/Win32` include - `Windowing/Content/EditorWindowContentController.h`. Host-visible content - state must cross through `Windowing/Host/EditorWindowContentBindings.h` and - `Windowing/Host/EditorWindowHostInterfaces.h`. -- Keep `EditorWindowNativePeer` frame/runtime communication data-shaped: - use `EditorNativeWindowRuntimeSurface`, `EditorNativeWindowFrameSnapshot`, - `EditorNativeWindowFrameCommands`, and small metrics snapshots instead of - exposing individual HWND, DPI, size, input, cursor, or title-bar getters to - app windowing. `EditorNativeWindowRuntimeSurface` must not expose a raw - native handle field. -- Do not let Win32 host code call `EditorWindowRuntimeController` or directly - drive editor runtime frames. Native messages may request immediate frames - through `EditorWindowHostCoordinator`; app windowing owns the render/update - step. -- Use direct authoritative workspace binding for ordinary in-window workspace - mutations. -- Use synchronization plans for operations that create, close, replace, or - reconcile workspace windows. -- Use frame transfer requests only for host-side or cross-window effects. +- Add reusable widgets, docking/workspace behavior, shell interaction, or field + logic to `include/XCEditor/**` and `src/**`, with unit coverage in + `tests/UI/Editor/unit`. +- Add product editor behavior to `app/Features/**`, then wire it through + `EditorShellAssetBuilder`, `EditorShellRuntime`, + `EditorShellHostedPanelCoordinator`, `EditorShellDrawComposer`, command + routing, and app state services as needed. +- Add new workspace panels by updating the panel ID constants, panel registry, + default workspace model, shell presentation, content dispatch, drawing, and + command/menu entries together. +- Add new utility windows through `EditorUtilityWindowKind`, + `EditorUtilityWindowRegistry`, an `EditorUtilityWindowPanel`, and the + context/request path. Do not model utility windows as workspace panels unless + they really dock inside the workspace. +- Add new commands in the command registry first, then menu/shortcut bindings, + host command bridge routing, and focused route tests. +- Keep workspace/window mutations transactional. Save the previous state, + validate after mutation, and roll back on invalid output, matching existing + controller patterns. +- Keep per-frame transient panel events separate from persistent app services. + Panels may emit frame events; `EditorContext` and runtime services own + persistent selection, command focus, project, and scene state. +- Release UI textures and GPU resources in `Shutdown` paths. D3D12 shutdown + should wait for GPU idle before releasing window resources. +- Do not write new manual-validation screenshots under the source tree. + Shared manual-validation hosts should write captures under the active build + directory. ## Current Architecture Debt -The highest-value windowing boundary has been hardened: `XCUIEditorLib` now -owns the reusable window authority, synchronization planner, workspace store, -and presentation projection under `XCEditor/Windowing`. App windowing remains -a source ownership boundary under `editor/app/Windowing`; it is not allowed to -be a separate production library target. The Win32 host is the concrete native -adapter and creates native host windows for app-owned `EditorWindowInstance` -objects supplied by app windowing. - -The framework/app compile boundary is also enforced. `XCUIEditorLib` does not -receive `editor/app` includes, and `XCUIEditorApp` does not directly compile -the shared framework sources. When framework UI code needs app-provided data -such as loaded icons, expose a framework-owned interface and adapt it in app -composition code. - -The top-level target debt is any app-internal static library target left in -the build. `XCUIEditorLib` must remain the only editor static library. If CMake -defines targets such as `XCUIEditorAppWindowing`, `XCUIEditorAppCore`, -`XCUIEditorAppLib`, or `XCUIEditorHost`, remove those target boundaries and -compile their app-side sources into `XCUIEditorApp`. - -The main windowing debt that was previously in the Win32 host has been cut: -frame iteration, immediate frame driving, content-controller construction, and -`EditorContext` ownership now live in app windowing. `EditorWindowHostCoordinator` -does not expose `GetEditorContext()`, and the native host receives an -app-owned `EditorWindowInstance` rather than raw workspace/utility content or a -runtime controller. - -The native-peer ownership cut has also been made: `EditorWindowManager` owns -`EditorWindowInstance` objects, each instance owns its -`EditorWindowRuntimeController`, and `editor/app/Platform/Win32/Windowing` -`EditorWindow` is a native peer for HWND/input/chrome/message integration. The -Win32 platform code must stay free of -`Windowing/Runtime/EditorWindowRuntimeController.h`. - -The native frame contract cut has also been made: frame/runtime initialization -no longer crosses the boundary through granular native-peer getters such as -HWND, DPI, size, input, cursor, workspace bounds, and title-bar mode. Win32 -captures those native facts into `EditorNativeWindowRuntimeSurface` and -`EditorNativeWindowFrameSnapshot`; app windowing renders from the snapshot and -returns native side effects through `EditorNativeWindowFrameCommands`. -`EditorNativeWindowRuntimeSurface` carries an abstract render surface object, -not a raw HWND or erased `void*`. - -The renderer ownership cut has also been made: app windowing no longer owns the -concrete D3D12 window render loop or Win32 surface setup. -`EditorWindowRuntimeController` consumes a backend-neutral -`Rendering::Host::EditorWindowRenderRuntime`, and `EditorWindowManager` receives -a backend-neutral `Rendering::Host::EditorWindowRenderRuntimeFactory`. The -current D3D12 factory is composed in `Application`, not in the Win32 host. The -current D3D12 runtime may recognize the concrete Win32 render surface adapter, -but app windowing must only traffic in the abstract rendering-host surface type. - -The platform-boundary cut has also been made: `XCUIEditorLib` trace code is -platform-neutral, and Win32 exception/DbgHelp stack capture lives under -`editor/app/Platform/Win32/Diagnostics`. Utility-window descriptors express -native shell intent with semantic host policy values rather than Win32 style -bits; the Win32 host maps those semantics to `WS_*` constants. - -The host/content binding cut has also been made: host-visible content binding -contracts live in `editor/app/Windowing/Host/EditorWindowContentBindings.h`. -`editor/app/Windowing/Content/EditorWindowContentController.h` owns concrete -content-controller contracts, while the Win32 native host consumes only the -small host binding interfaces exposed from `Windowing/Host`. - -The remaining promotion debt is the app runtime surface and host contract -vocabulary itself. -`editor/app/Windowing` is still app-internal and may depend on app semantics -such as `EditorContext`, `EditorShellRuntime`, utility window descriptors, and -product-specific content. This app-internal dependency is a directory-level -ownership detail only; it must not become a separate static library boundary. -Do not promote host interfaces, frame transfer, runtime controllers, content -controllers, or render-runtime contracts to `XCEditor` until they are generic -enough to expose. Do not move frame ownership back into -`editor/app/Platform/Win32`, do not move concrete renderer ownership back into -`editor/app/Windowing`, and do not move renderer factory ownership back into -the Win32 host. - -Do not take another library-boundary architecture cut just to keep carving this -area. After the native-peer and native-frame-contract cuts, the next default -improvement should be boundary guardrails, such as checks that keep -`editor/app/Windowing` free of `Rendering/D3D12`, `Platform/Win32`, -`windows.h`, HWND types, raw native render handles, and one-off native-peer -frame getters; keep app semantics free of Win32 `WS_*` constants; keep -`editor/include/XCEditor` and `editor/src` free of Win32 diagnostics and -exception types; and keep `editor/app/Platform/Win32` free of `Rendering/D3D12` -and `Windowing/Runtime/EditorWindowRuntimeController.h`; keep -`editor/app/Platform/Win32` free of -`Windowing/Content/EditorWindowContentController.h`. Consider another structural -source-directory cut only when there is concrete pressure, such as another -native host, another render backend, or headless editor/window tests; do not -satisfy that pressure by adding another production static library. +- `XCEditor` is the intentional single executable app target. App-layer + boundaries are maintained through directory ownership, namespaces, app/service + interfaces, focused reusable-layer tests, manual-validation hosts, and smoke + diagnostics, not through internal app static-library targets. +- Legacy app-split CMake targets have been removed. Do not reference + `XCUIEditorAppLib`, `XCUIEditorAppCore`, or `XCUIEditorHost` in new build + logic or tests. +- Existing source-tree capture history is present under some manual-validation + scenarios, but new captures should go to the build output directory. +- Runtime trace files are the main app smoke diagnostic. Avoid replacing + trace-backed diagnostics with UI-only feedback that tests cannot observe. ## Validation -Default editor validation is only the app build plus the 12-second smoke run: - -```powershell -cmake --build build --config Debug --target editor_ui_smoke_targets -build\tests\UI\Editor\smoke\Debug\editor_ui_smoke_runner.exe build\editor\Debug\XCEngine.exe -``` - -Do not run `editor_windowing_phase1_tests`, `editor_ui_tests`, or broader test -targets by default. Run them only when the user explicitly asks for them or a -separate targeted change makes them necessary. - -The runner sets `XCUIEDITOR_SMOKE_TEST_DURATION_SECONDS=12`, waits for the -editor to launch, lets the app auto-exit, and treats a clean editor exit as -success. +- Build shared editor UI after reusable-layer changes: + `cmake --build --config Debug --target XCUIEditor`. +- Build the app after startup, windowing, rendering, feature-panel, or resource + changes: + `cmake --build --config Debug --target XCEditor`. +- Build reusable editor unit tests: + `cmake --build --config Debug --target editor_ui_tests`. +- Build window synchronization tests: + `cmake --build --config Debug --target editor_windowing_phase1_tests`. +- Build aggregate editor unit targets: + `cmake --build --config Debug --target editor_ui_unit_tests`. +- Build app smoke support: + `cmake --build --config Debug --target editor_ui_smoke_targets`. +- Run app smoke through CTest when `XCEditor` is enabled: + `ctest -C Debug -R xceditor_smoke --output-on-failure`. +- Useful environment flags: + `XCUIEDITOR_VERBOSE_TRACE=1`, `XCUI_AUTO_CAPTURE_ON_STARTUP=1`, + `XCUIEDITOR_SMOKE_TEST=1`, `XCUIEDITOR_SMOKE_TEST_DURATION_SECONDS=`, + and `XCUIEDITOR_SMOKE_TEST_FRAME_LIMIT=`. ## Recommended Reading -Start with these files for editor/windowing work: - - `editor/CMakeLists.txt` -- `editor/app/Bootstrap/Application.*` -- `editor/app/Composition/EditorContext.*` -- `editor/app/Composition/EditorShellRuntime.*` +- `editor/app/Bootstrap/Application.cpp` +- `editor/app/Composition/EditorContext.cpp` +- `editor/app/Composition/EditorShellRuntime.cpp` +- `editor/app/Composition/EditorShellAssetBuilder.cpp` +- `editor/app/Windowing/EditorWindowManager.cpp` +- `editor/app/Windowing/EditorWindowInstance.cpp` +- `editor/app/Windowing/Content/EditorWorkspaceWindowContentController.cpp` +- `editor/app/Windowing/Frame/EditorWindowFrameOrchestrator.cpp` +- `editor/app/Windowing/Coordinator/EditorWindowWorkspaceCoordinator.cpp` +- `editor/include/XCEditor/Windowing/System/EditorWindowSystem.h` +- `editor/src/Windowing/System/EditorWindowSystem.cpp` - `editor/include/XCEditor/Workspace/UIEditorWorkspaceController.h` - `editor/src/Workspace/UIEditorWorkspaceController.cpp` -- `editor/include/XCEditor/Windowing/System/EditorWindowSystem.h` -- `editor/include/XCEditor/Windowing/System/EditorWindowSynchronizationPlan.h` -- `editor/include/XCEditor/Windowing/System/EditorWindowSynchronizationPlanner.h` -- `editor/include/XCEditor/Windowing/Presentation/EditorWorkspaceWindowProjection.h` -- `editor/include/XCEditor/Windowing/Presentation/EditorWindowPresentationPolicy.h` -- `editor/src/Windowing/System/EditorWindowSystem.cpp` -- `editor/src/Windowing/System/EditorWindowWorkspaceStore.*` -- `editor/src/Windowing/System/EditorWindowSynchronizationPlanner.cpp` -- `editor/src/Windowing/Presentation/EditorWindowPresentationPolicy.cpp` -- `editor/app/Windowing/Host/EditorWindowContentBindings.h` -- `editor/app/Windowing/Host/EditorWindowHostInterfaces.h` -- `editor/app/Windowing/Content/EditorWindowContentController.h` -- `editor/app/Windowing/Content/EditorWindowContentFactory.*` -- `editor/app/Windowing/Content/EditorWorkspaceWindowContentController.*` -- `editor/app/Windowing/Frame/EditorWindowFrameOrchestrator.*` -- `editor/app/Windowing/Frame/EditorWindowTransferRequests.h` -- `editor/app/Windowing/Runtime/EditorWindowRuntimeController.*` -- `editor/app/Windowing/Runtime/EditorWindowScreenshotController.*` -- `editor/app/Windowing/EditorWindowInstance.*` -- `editor/app/Windowing/Coordinator/EditorWindowWorkspaceCoordinator.*` -- `editor/app/Windowing/Coordinator/EditorUtilityWindowCoordinator.*` -- `editor/app/Windowing/EditorWindowManager.*` +- `editor/include/XCEditor/Workspace/UIEditorWindowWorkspaceController.h` +- `editor/src/Workspace/UIEditorWindowWorkspaceController.cpp` +- `editor/app/Platform/Win32/Windowing/EditorWindowMessageDispatcher.cpp` - `editor/app/Rendering/Host/EditorWindowRenderRuntime.h` -- `editor/app/Rendering/D3D12/D3D12EditorWindowRenderRuntime.*` -- `editor/app/Platform/Win32/Diagnostics/Win32CrashTrace.*` -- `editor/app/Platform/Win32/Windowing/Win32EditorWindowRenderRuntimeSurface.h` -- `editor/app/Platform/Win32/Windowing/EditorWindow.*` -- `editor/app/Platform/Win32/Windowing/EditorWindowHostRuntime.*` -- `editor/app/Platform/Win32/Windowing/EditorWindowMessageDispatcher.*` +- `editor/app/Rendering/Viewport/ViewportHostService.h` +- `tests/UI/Editor/unit/CMakeLists.txt` - `tests/UI/Editor/smoke/CMakeLists.txt` +- `tests/UI/Editor/manual_validation/README.md` ## Recent Cuts -- The framework-to-app icon dependency is sealed: `UIEditorShellCompose` uses - the framework-owned `UIEditorShellIconResolver`, and the app adapts - `BuiltInIcons` in `EditorShellDrawComposer`. -- The framework/app compile boundary is sealed: `XCUIEditorLib` does not receive - `editor/app` includes, `XCUIEditorApp` does not directly compile - `${XCUI_EDITOR_SHARED_SOURCES}`, and the app consumes framework code through - `XCUIEditorLib`. -- The reusable window authority core lives in the framework: - `EditorWindowSystem`, synchronization planning, workspace store, and - presentation projection are under `editor/include/XCEditor/Windowing` and - `editor/src/Windowing`. -- App windowing owns the runtime cut: content controllers, - `EditorWindowRuntimeController`, frame driving, frame transfer, host - contracts, and `EditorWindowManager` are under `editor/app/Windowing` as an - app source directory, not as a standalone library target; Win32 remains the - native adapter and no longer exposes `EditorContext`. -- The native-peer ownership cut is sealed: app windowing now owns live - `EditorWindowInstance` objects, those instances own - `EditorWindowRuntimeController`, and Win32 `EditorWindow` only owns the - native peer side for HWND/input/chrome/message work. `CreateHostWindow(...)` - binds a native peer to an existing `EditorHostWindow`; it does not receive a - runtime controller. -- The native frame contract cut is sealed: app windowing consumes - `EditorNativeWindowRuntimeSurface` and `EditorNativeWindowFrameSnapshot` - instead of calling granular native-peer getters for frame/runtime data, and - Win32 applies frame side effects through `EditorNativeWindowFrameCommands`. - Runtime surface creation carries an abstract - `Rendering::Host::EditorWindowRenderRuntimeSurface`, not a raw HWND/`void*`. -- The concrete renderer cut is sealed: app windowing consumes - `Rendering::Host::EditorWindowRenderRuntime` and - `Rendering::Host::EditorWindowRenderRuntimeFactory`, while the current D3D12 - implementation and factory live under `editor/app/Rendering/D3D12`. The - factory is composed in `Application`; `editor/app/Windowing` should stay free - of `Rendering/D3D12`, `windows.h`, and HWND types, and - `editor/app/Platform/Win32` should stay free of `Rendering/D3D12`. -- The Win32 platform-boundary cut is sealed: framework runtime trace code no - longer includes Win32/DbgHelp or exposes `_EXCEPTION_POINTERS`; Win32 crash - stack capture lives under `editor/app/Platform/Win32/Diagnostics`; utility - window descriptors use semantic native host policies instead of `WS_*` - constants. -- The host/content binding cut is sealed: native host-visible content binding - contracts live under `editor/app/Windowing/Host`, and Win32 code consumes - `EditorWindowContentBindings.h` instead of the content-controller contract. -- The production target shape is sealed: `XCUIEditorLib` is the only editor - static library, and all app-side source directories compile into - `XCUIEditorApp`. -- Default validation remains the editor app build plus the 12-second smoke run; - run broader windowing/unit targets only for targeted coverage. +This section is intentionally important. Keep it as the running ledger of +architecture cuts that have already been made, so future agents do not +re-litigate or accidentally undo them. Add concrete entries here whenever a +change closes a boundary, removes an obsolete path, or establishes a new +ownership rule. + +- Primary workspace state is bootstrapped into `EditorWindowSystem` before + native window creation. +- Workspace content now pulls a live authoritative workspace controller every + frame instead of trusting a stale local copy. +- Panel detach and cross-window tab drag are frame transfer requests handled by + `EditorWindowWorkspaceCoordinator`, then synchronized through + `EditorWindowSynchronizationPlanner`. +- Utility windows are app content controllers backed by + `EditorUtilityWindowPanel`; they are not workspace windows. +- Viewport rendering is routed through `ViewportHostService` and the per-window + render runtime rather than directly from shell composition. +- The old app-split target residue was removed from CMake and tests. The app + remains a single `XCEditor` target with output name `XCEngine`, and + manual-validation hosts use the shared Core UI validation host instead of an + editor app host target. diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 70fed00d..cc417e6f 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -22,7 +22,7 @@ endfunction() if(XCENGINE_BUILD_XCUI_EDITOR_APP AND NOT XCENGINE_ENABLE_RENDERING_EDITOR_SUPPORT) message(FATAL_ERROR - "XCUIEditorApp requires XCENGINE_ENABLE_RENDERING_EDITOR_SUPPORT=ON") + "XCEditor requires XCENGINE_ENABLE_RENDERING_EDITOR_SUPPORT=ON") endif() set(XCUI_EDITOR_FOUNDATION_SOURCES @@ -157,24 +157,24 @@ set(XCUI_EDITOR_SHARED_SOURCES ${XCUI_EDITOR_WIDGET_SUPPORT_SOURCES} ) -add_library(XCUIEditorLib STATIC +add_library(XCUIEditor STATIC ${XCUI_EDITOR_SHARED_SOURCES} ) -target_include_directories(XCUIEditorLib PUBLIC +target_include_directories(XCUIEditor PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/engine/include ) -target_include_directories(XCUIEditorLib PRIVATE +target_include_directories(XCUIEditor PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ) -target_link_libraries(XCUIEditorLib PUBLIC +target_link_libraries(XCUIEditor PUBLIC XCEngine ) -xcui_editor_apply_common_target_settings(XCUIEditorLib PUBLIC) +xcui_editor_apply_common_target_settings(XCUIEditor PUBLIC) set(XCUI_EDITOR_APP_WINDOWING_SOURCES app/Windowing/EditorWindowInstance.cpp @@ -309,27 +309,27 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP) ${XCUI_EDITOR_APP_PLATFORM_SOURCES} ) - add_executable(XCUIEditorApp WIN32 + add_executable(XCEditor WIN32 ${XCUI_EDITOR_APP_BOOTSTRAP_SOURCES} ${XCUI_EDITOR_APP_INTERNAL_SOURCES} ) - target_include_directories(XCUIEditorApp PRIVATE + target_include_directories(XCEditor PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/app ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/engine/include ${CMAKE_SOURCE_DIR}/engine/third_party/stb ) - target_compile_definitions(XCUIEditorApp PRIVATE + target_compile_definitions(XCEditor PRIVATE XCUIEDITOR_REPO_ROOT="${XCUIEDITOR_REPO_ROOT_PATH}" ) - xcui_editor_apply_common_target_settings(XCUIEditorApp PRIVATE) + xcui_editor_apply_common_target_settings(XCEditor PRIVATE) - target_link_libraries(XCUIEditorApp PRIVATE + target_link_libraries(XCEditor PRIVATE XCEngine - XCUIEditorLib + XCUIEditor XCEngineRenderingEditorSupport d3d12.lib d3dcompiler.lib @@ -339,29 +339,20 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP) windowscodecs.lib ) - set_target_properties(XCUIEditorApp PROPERTIES + set_target_properties(XCEditor PROPERTIES OUTPUT_NAME "XCEngine" ) if(WIN32 AND EXISTS "${CMAKE_SOURCE_DIR}/engine/third_party/assimp/bin/assimp-vc143-mt.dll") - add_custom_command(TARGET XCUIEditorApp POST_BUILD + add_custom_command(TARGET XCEditor POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/engine/third_party/assimp/bin/assimp-vc143-mt.dll - $/assimp-vc143-mt.dll + $/assimp-vc143-mt.dll ) endif() - add_custom_command(TARGET XCUIEditorApp POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rm -f - $/XCUIEditorAppCore.lib - $/XCUIEditorAppLib.lib - $/XCUIEditorHost.lib - $/XCUIEditorLib.lib - $/XCUIEditor.exe - ) - if(WIN32 AND XCENGINE_ENABLE_PHYSX) - xcengine_copy_physx_runtime_dlls(XCUIEditorApp) + xcengine_copy_physx_runtime_dlls(XCEditor) endif() endif() diff --git a/editor/app/Bootstrap/Application.cpp b/editor/app/Bootstrap/Application.cpp index bc79ca35..766d44da 100644 --- a/editor/app/Bootstrap/Application.cpp +++ b/editor/app/Bootstrap/Application.cpp @@ -96,7 +96,7 @@ Application::Application() Application::~Application() = default; -int RunXCUIEditorApp(HINSTANCE hInstance, int nCmdShow) { +int RunXCEditor(HINSTANCE hInstance, int nCmdShow) { Application application; return application.Run(hInstance, nCmdShow); } diff --git a/editor/app/Bootstrap/Application.h b/editor/app/Bootstrap/Application.h index 4edbfba9..bbc32b2d 100644 --- a/editor/app/Bootstrap/Application.h +++ b/editor/app/Bootstrap/Application.h @@ -68,7 +68,7 @@ private: bool m_smokeTestCloseRequested = false; }; -int RunXCUIEditorApp(HINSTANCE hInstance, int nCmdShow); +int RunXCEditor(HINSTANCE hInstance, int nCmdShow); } // namespace XCEngine::UI::Editor diff --git a/editor/app/Platform/Win32/InputModifierTracker.h b/editor/app/Platform/Win32/InputModifierTracker.h new file mode 100644 index 00000000..171bf39e --- /dev/null +++ b/editor/app/Platform/Win32/InputModifierTracker.h @@ -0,0 +1,3 @@ +#pragma once + +#include "Runtime/InputModifierTracker.h" diff --git a/editor/app/main.cpp b/editor/app/main.cpp index 0ff38cec..72140a93 100644 --- a/editor/app/main.cpp +++ b/editor/app/main.cpp @@ -1,5 +1,5 @@ #include "Bootstrap/Application.h" int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow) { - return XCEngine::UI::Editor::RunXCUIEditorApp(hInstance, nCmdShow); + return XCEngine::UI::Editor::RunXCEditor(hInstance, nCmdShow); } diff --git a/managed/GameScripts/RenderPipelineApiProbe.cs b/managed/GameScripts/RenderPipelineApiProbe.cs index 68bbee76..70792b1b 100644 --- a/managed/GameScripts/RenderPipelineApiProbe.cs +++ b/managed/GameScripts/RenderPipelineApiProbe.cs @@ -346,7 +346,6 @@ namespace Gameplay private readonly DrawObjectsPass m_shadowCasterPass = new DrawObjectsPass( RenderPassEvent.BeforeRenderingShadows, - SceneRenderPhase.Opaque, RendererListDesc.CreateDefault( RendererListType.ShadowCaster)); diff --git a/managed/GameScripts/ScriptableRenderContextApiSurfaceProbe.cs b/managed/GameScripts/ScriptableRenderContextApiSurfaceProbe.cs index c8bdb71d..9a3876f7 100644 --- a/managed/GameScripts/ScriptableRenderContextApiSurfaceProbe.cs +++ b/managed/GameScripts/ScriptableRenderContextApiSurfaceProbe.cs @@ -193,6 +193,9 @@ namespace Gameplay typeof(CommandBuffer); System.Type profilingSamplerType = typeof(ProfilingSampler); + System.Type sceneRenderPhaseType = + contextType.Assembly.GetType( + "XCEngine.Rendering.SceneRenderPhase"); System.Type contextItemType = typeof(ContextItem); System.Type contextContainerType = @@ -231,7 +234,6 @@ namespace Gameplay null, new System.Type[] { - typeof(SceneRenderPhase), typeof(RendererListType) }, null) != null; @@ -242,7 +244,6 @@ namespace Gameplay null, new System.Type[] { - typeof(SceneRenderPhase), typeof(RendererListDesc) }, null) != null; @@ -253,7 +254,6 @@ namespace Gameplay null, new System.Type[] { - typeof(SceneRenderPhase), typeof(RendererListDesc), typeof(DrawingSettings) }, @@ -513,8 +513,8 @@ namespace Gameplay BindingFlags.Instance | BindingFlags.Public) != null; HasSceneRenderPhaseType = - contextType.Assembly.GetType( - "XCEngine.Rendering.SceneRenderPhase") != null; + sceneRenderPhaseType != null && + sceneRenderPhaseType.IsPublic; HasSceneRenderInjectionPointType = contextType.Assembly.GetType( "XCEngine.Rendering.SceneRenderInjectionPoint") != null; diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DrawObjectsPass.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DrawObjectsPass.cs index a66e83e7..9c4f6cc2 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DrawObjectsPass.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DrawObjectsPass.cs @@ -5,8 +5,6 @@ namespace XCEngine.Rendering.Universal { public sealed class DrawObjectsPass : ScriptableRenderPass { - private SceneRenderPhase m_scenePhase = - SceneRenderPhase.Opaque; private RendererListDesc m_rendererListDesc = RendererListDesc.CreateDefault( RendererListType.Opaque); @@ -15,11 +13,9 @@ namespace XCEngine.Rendering.Universal public DrawObjectsPass( RenderPassEvent passEvent, - SceneRenderPhase scenePhase, RendererListDesc rendererListDesc) : this( passEvent, - scenePhase, rendererListDesc, DrawingSettings.CreateDefault()) { @@ -27,37 +23,31 @@ namespace XCEngine.Rendering.Universal public DrawObjectsPass( RenderPassEvent passEvent, - SceneRenderPhase scenePhase, RendererListDesc rendererListDesc, DrawingSettings drawingSettings) { Configure( passEvent, - scenePhase, rendererListDesc, drawingSettings); } public void Configure( RenderPassEvent passEvent, - SceneRenderPhase scenePhase, RendererListDesc rendererListDesc) { Configure( passEvent, - scenePhase, rendererListDesc, DrawingSettings.CreateDefault()); } public void Configure( RenderPassEvent passEvent, - SceneRenderPhase scenePhase, RendererListDesc rendererListDesc, DrawingSettings drawingSettings) { renderPassEvent = passEvent; - m_scenePhase = scenePhase; m_rendererListDesc = rendererListDesc; m_drawingSettings = drawingSettings; } @@ -70,7 +60,6 @@ namespace XCEngine.Rendering.Universal renderingData != null && renderingData.isSceneDrawStage && context.DrawRenderers( - m_scenePhase, m_rendererListDesc, m_drawingSettings); } diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsFeatureSettings.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsFeatureSettings.cs index 1af57570..79a881eb 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsFeatureSettings.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsFeatureSettings.cs @@ -7,8 +7,6 @@ namespace XCEngine.Rendering.Universal { public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingOpaques; - public SceneRenderPhase scenePhase = - SceneRenderPhase.Opaque; public RendererListDesc rendererListDesc = RendererListDesc.CreateDefault( RendererListType.Opaque); @@ -21,9 +19,6 @@ namespace XCEngine.Rendering.Universal hash = RuntimeStateHashUtility.Combine( hash, (int)passEvent); - hash = RuntimeStateHashUtility.Combine( - hash, - (int)scenePhase); hash = RuntimeStateHashUtility.Combine( hash, rendererListDesc); diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs index 313252ed..f19e4aa2 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs @@ -12,8 +12,6 @@ namespace XCEngine.Rendering.Universal public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingOpaques; - public SceneRenderPhase scenePhase = - SceneRenderPhase.Opaque; public RendererListType rendererListType = RendererListType.Opaque; public bool overrideRenderQueueRange; @@ -67,7 +65,6 @@ namespace XCEngine.Rendering.Universal return new RenderObjectsFeatureSettings { passEvent = passEvent, - scenePhase = scenePhase, rendererListDesc = BuildRendererListDesc(), drawingSettings = BuildDrawingSettings() }; diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalDepthPrepassBlock.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalDepthPrepassBlock.cs index b350a18a..9edfbdbc 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalDepthPrepassBlock.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalDepthPrepassBlock.cs @@ -8,7 +8,6 @@ namespace XCEngine.Rendering.Universal private readonly DrawObjectsPass m_drawDepthPrepass = new DrawObjectsPass( RenderPassEvent.BeforeRenderingPrePasses, - SceneRenderPhase.Opaque, RendererListDesc.CreateDefault( RendererListType.Opaque)); @@ -44,7 +43,6 @@ namespace XCEngine.Rendering.Universal m_drawDepthPrepass.Configure( depthPrepass.passEvent, - SceneRenderPhase.Opaque, depthPrepass.rendererListDesc, depthPrepass.drawingSettings); renderer.EnqueuePass(m_drawDepthPrepass); diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalMainSceneBlock.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalMainSceneBlock.cs index 92f6a730..a6396bbc 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalMainSceneBlock.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalMainSceneBlock.cs @@ -10,7 +10,6 @@ namespace XCEngine.Rendering.Universal private readonly DrawObjectsPass m_drawOpaqueObjectsPass = new DrawObjectsPass( RenderPassEvent.RenderOpaques, - SceneRenderPhase.Opaque, RendererListDesc.CreateDefault( RendererListType.Opaque)); private readonly DrawSkyboxPass m_drawSkyboxPass = @@ -18,7 +17,6 @@ namespace XCEngine.Rendering.Universal private readonly DrawObjectsPass m_drawTransparentObjectsPass = new DrawObjectsPass( RenderPassEvent.RenderTransparents, - SceneRenderPhase.Transparent, RendererListDesc.CreateDefault( RendererListType.Transparent)); @@ -94,7 +92,6 @@ namespace XCEngine.Rendering.Universal { m_drawOpaqueObjectsPass.Configure( mainScene.opaquePassEvent, - SceneRenderPhase.Opaque, mainScene.opaqueRendererListDesc, mainScene.opaqueDrawingSettings); renderer.EnqueuePass(m_drawOpaqueObjectsPass); @@ -115,7 +112,6 @@ namespace XCEngine.Rendering.Universal { m_drawTransparentObjectsPass.Configure( mainScene.transparentPassEvent, - SceneRenderPhase.Transparent, mainScene.transparentRendererListDesc, mainScene.transparentDrawingSettings); renderer.EnqueuePass( diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderObjectsFeatureController.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderObjectsFeatureController.cs index 202fb688..b093a8a5 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderObjectsFeatureController.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderObjectsFeatureController.cs @@ -29,7 +29,6 @@ namespace XCEngine.Rendering.Universal m_pass = new DrawObjectsPass( settings.passEvent, - settings.scenePhase, settings.rendererListDesc, settings.drawingSettings); return; @@ -37,7 +36,6 @@ namespace XCEngine.Rendering.Universal m_pass.Configure( settings.passEvent, - settings.scenePhase, settings.rendererListDesc, settings.drawingSettings); } diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalShadowCasterBlock.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalShadowCasterBlock.cs index a6af6b35..6c7e1b06 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalShadowCasterBlock.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalShadowCasterBlock.cs @@ -8,7 +8,6 @@ namespace XCEngine.Rendering.Universal private readonly DrawObjectsPass m_drawShadowCasterPass = new DrawObjectsPass( RenderPassEvent.BeforeRenderingShadows, - SceneRenderPhase.Opaque, RendererListDesc.CreateDefault( RendererListType.ShadowCaster)); @@ -64,7 +63,6 @@ namespace XCEngine.Rendering.Universal m_drawShadowCasterPass.Configure( shadowCaster.passEvent, - SceneRenderPhase.Opaque, shadowCaster.rendererListDesc, shadowCaster.drawingSettings); renderer.EnqueuePass(m_drawShadowCasterPass); diff --git a/managed/XCEngine.ScriptCore/Rendering/Core/SceneRenderPhase.cs b/managed/XCEngine.ScriptCore/Rendering/Core/SceneRenderPhase.cs index 0dd5c35f..b335cbf3 100644 --- a/managed/XCEngine.ScriptCore/Rendering/Core/SceneRenderPhase.cs +++ b/managed/XCEngine.ScriptCore/Rendering/Core/SceneRenderPhase.cs @@ -1,6 +1,6 @@ namespace XCEngine.Rendering { - public enum SceneRenderPhase + internal enum SceneRenderPhase { Opaque = 0, Skybox = 1, diff --git a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs index be00ffdc..48faf985 100644 --- a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs +++ b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs @@ -58,38 +58,42 @@ namespace XCEngine.Rendering } public bool DrawRenderers( - SceneRenderPhase scenePhase, RendererListType rendererListType) { return DrawRenderers( - scenePhase, rendererListType, DrawingSettings.CreateDefault()); } public bool DrawRenderers( - SceneRenderPhase scenePhase, RendererListType rendererListType, DrawingSettings drawingSettings) { return DrawRenderers( - scenePhase, RendererListDesc.CreateDefault( rendererListType), drawingSettings); } public bool DrawRenderers( - SceneRenderPhase scenePhase, RendererListDesc rendererListDesc) { return DrawRenderers( - scenePhase, rendererListDesc, DrawingSettings.CreateDefault()); } public bool DrawRenderers( + RendererListDesc rendererListDesc, + DrawingSettings drawingSettings) + { + return DrawRenderers( + ResolveSceneRenderPhase(rendererListDesc), + rendererListDesc, + drawingSettings); + } + + internal bool DrawRenderers( SceneRenderPhase scenePhase, RendererListDesc rendererListDesc, DrawingSettings drawingSettings) @@ -117,7 +121,6 @@ namespace XCEngine.Rendering public bool DrawOpaqueRenderers() { return DrawRenderers( - SceneRenderPhase.Opaque, RendererListDesc.CreateDefault( RendererListType.Opaque)); } @@ -125,7 +128,6 @@ namespace XCEngine.Rendering public bool DrawTransparentRenderers() { return DrawRenderers( - SceneRenderPhase.Transparent, RendererListDesc.CreateDefault( RendererListType.Transparent)); } @@ -177,6 +179,21 @@ namespace XCEngine.Rendering internal ulong nativeHandle => m_nativeHandle; + + private static SceneRenderPhase ResolveSceneRenderPhase( + RendererListDesc rendererListDesc) + { + switch (rendererListDesc.type) + { + case RendererListType.Transparent: + return SceneRenderPhase.Transparent; + case RendererListType.Opaque: + case RendererListType.ShadowCaster: + case RendererListType.AllVisible: + default: + return SceneRenderPhase.Opaque; + } + } } } diff --git a/project/Assets/Scripts/ProjectRenderPipelineProbe.cs b/project/Assets/Scripts/ProjectRenderPipelineProbe.cs index 7bafb0f2..4e29b65f 100644 --- a/project/Assets/Scripts/ProjectRenderPipelineProbe.cs +++ b/project/Assets/Scripts/ProjectRenderPipelineProbe.cs @@ -148,8 +148,6 @@ namespace ProjectScripts { passEvent = RenderPassEvent.RenderOpaques, - scenePhase = - SceneRenderPhase.Opaque, shaderPassName = "Unlit", overrideMaterialPath = @@ -192,7 +190,6 @@ namespace ProjectScripts private readonly DrawObjectsPass m_opaquePass = new DrawObjectsPass( RenderPassEvent.RenderOpaques, - SceneRenderPhase.Opaque, RendererListDesc.CreateDefault( RendererListType.Opaque)); diff --git a/tests/TEST_SPEC.md b/tests/TEST_SPEC.md index f6cc145c..a157dfd7 100644 --- a/tests/TEST_SPEC.md +++ b/tests/TEST_SPEC.md @@ -196,7 +196,7 @@ ctest --test-dir build -C Debug --output-on-failure 补充说明: - 该入口当前刻意不依赖 `editor_ui_tests`。 -- `xcui_editor_app_smoke` 当前保留为可选补充验证,不再作为默认构建门槛。 +- `xceditor_smoke` 当前保留为可选补充验证,不再作为默认构建门槛。 - 如果要在现有产物上补跑 smoke,使用 `powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\Run-RendererPhaseRegression.ps1 -RepoRoot . -BuildDir .\build -Config Debug -SkipBuild -IncludeSmoke`。 - `ctest -N` 现在应能正常完成枚举;输出里的 `*_NOT_BUILT` 占位项表示目标尚未构建,不再表示 discover/include 生成损坏。 diff --git a/tests/UI/Editor/manual_validation/CMakeLists.txt b/tests/UI/Editor/manual_validation/CMakeLists.txt index cae4b30c..1536be67 100644 --- a/tests/UI/Editor/manual_validation/CMakeLists.txt +++ b/tests/UI/Editor/manual_validation/CMakeLists.txt @@ -22,7 +22,7 @@ function(xcengine_configure_editor_ui_integration_validation_target target) endif() target_link_libraries(${target} PRIVATE - XCUIEditorLib + XCUIEditor editor_ui_integration_host ) diff --git a/tests/UI/Editor/manual_validation/shared/CMakeLists.txt b/tests/UI/Editor/manual_validation/shared/CMakeLists.txt index e0e82e90..745ee027 100644 --- a/tests/UI/Editor/manual_validation/shared/CMakeLists.txt +++ b/tests/UI/Editor/manual_validation/shared/CMakeLists.txt @@ -28,6 +28,7 @@ add_library(editor_ui_integration_host STATIC target_include_directories(editor_ui_integration_host PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/tests/UI/Core/integration/shared/src ${CMAKE_SOURCE_DIR}/engine/include ${XCENGINE_EDITOR_UI_TESTS_EDITOR_ROOT}/include ${XCENGINE_EDITOR_UI_TESTS_EDITOR_ROOT} @@ -51,6 +52,6 @@ endif() target_link_libraries(editor_ui_integration_host PUBLIC editor_ui_validation_registry - XCUIEditorHost + core_ui_integration_host XCEngine ) diff --git a/tests/UI/Editor/manual_validation/shared/src/EditorValidationScenario.cpp b/tests/UI/Editor/manual_validation/shared/src/EditorValidationScenario.cpp index 16962d16..2060e62e 100644 --- a/tests/UI/Editor/manual_validation/shared/src/EditorValidationScenario.cpp +++ b/tests/UI/Editor/manual_validation/shared/src/EditorValidationScenario.cpp @@ -31,7 +31,7 @@ const std::array& GetEditorValidationScenarios() { "editor.shell.workspace_shell_compose", UIValidationDomain::Editor, "shell", - "Editor 壳层 | 工作区组?, + "Editor Shell | Workspace Shell Compose", RepoRelative("tests/UI/Editor/manual_validation/shell/workspace_shell_compose/View.xcui"), RepoRelative("tests/UI/Editor/manual_validation/shell/workspace_shell_compose/captures") } diff --git a/tests/UI/Editor/manual_validation/shared/src/Rendering/Native/AutoScreenshot.h b/tests/UI/Editor/manual_validation/shared/src/Rendering/Native/AutoScreenshot.h new file mode 100644 index 00000000..de5e5752 --- /dev/null +++ b/tests/UI/Editor/manual_validation/shared/src/Rendering/Native/AutoScreenshot.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace XCEngine::UI::Editor::Host { + +using AutoScreenshotController = + ::XCEngine::Tests::CoreUI::Host::AutoScreenshotController; + +} // namespace XCEngine::UI::Editor::Host diff --git a/tests/UI/Editor/manual_validation/shared/src/Rendering/Native/NativeRenderer.h b/tests/UI/Editor/manual_validation/shared/src/Rendering/Native/NativeRenderer.h new file mode 100644 index 00000000..bb0d1088 --- /dev/null +++ b/tests/UI/Editor/manual_validation/shared/src/Rendering/Native/NativeRenderer.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace XCEngine::UI::Editor::Host { + +using NativeRenderer = ::XCEngine::Tests::CoreUI::Host::NativeRenderer; + +} // namespace XCEngine::UI::Editor::Host diff --git a/tests/UI/Editor/smoke/CMakeLists.txt b/tests/UI/Editor/smoke/CMakeLists.txt index 6c280214..cbe9ad7f 100644 --- a/tests/UI/Editor/smoke/CMakeLists.txt +++ b/tests/UI/Editor/smoke/CMakeLists.txt @@ -1,10 +1,10 @@ -if(NOT TARGET XCUIEditorApp) +if(NOT TARGET XCEditor) add_custom_target(editor_ui_smoke_targets) return() endif() add_executable(editor_ui_smoke_runner - xcui_editor_app_smoke_runner.cpp + xceditor_smoke_runner.cpp ) target_link_libraries(editor_ui_smoke_runner @@ -19,12 +19,12 @@ if(MSVC) endif() add_test( - NAME xcui_editor_app_smoke + NAME xceditor_smoke COMMAND $ - $ + $ ) -set_tests_properties(xcui_editor_app_smoke PROPERTIES +set_tests_properties(xceditor_smoke PROPERTIES TIMEOUT 45 RUN_SERIAL TRUE WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} @@ -33,5 +33,5 @@ set_tests_properties(xcui_editor_app_smoke PROPERTIES add_custom_target(editor_ui_smoke_targets DEPENDS editor_ui_smoke_runner - XCUIEditorApp + XCEditor ) diff --git a/tests/UI/Editor/smoke/xcui_editor_app_smoke_runner.cpp b/tests/UI/Editor/smoke/xceditor_smoke_runner.cpp similarity index 97% rename from tests/UI/Editor/smoke/xcui_editor_app_smoke_runner.cpp rename to tests/UI/Editor/smoke/xceditor_smoke_runner.cpp index 9817b244..78c6bb4e 100644 --- a/tests/UI/Editor/smoke/xcui_editor_app_smoke_runner.cpp +++ b/tests/UI/Editor/smoke/xceditor_smoke_runner.cpp @@ -32,7 +32,7 @@ std::wstring QuoteCommandLine(const std::filesystem::path& executablePath) { } void PrintFailure(std::string_view message) { - std::cerr << "[xcui_editor_app_smoke] " << message << '\n'; + std::cerr << "[xceditor_smoke] " << message << '\n'; } std::string ReadTextFile(const std::filesystem::path& path) { @@ -238,13 +238,13 @@ void CloseProcessHandles(PROCESS_INFORMATION& processInfo) { int wmain(int argc, wchar_t* argv[]) { if (argc < 2 || argv[1] == nullptr || argv[1][0] == L'\0') { - PrintFailure("missing XCUIEditorApp path"); + PrintFailure("missing XCEditor path"); return 1; } const std::filesystem::path executablePath = std::filesystem::path(argv[1]).lexically_normal(); if (!std::filesystem::exists(executablePath)) { - PrintFailure("XCUIEditorApp not found: " + executablePath.string()); + PrintFailure("XCEditor not found: " + executablePath.string()); return 1; } @@ -260,7 +260,7 @@ int wmain(int argc, wchar_t* argv[]) { PROCESS_INFORMATION processInfo = {}; if (!LaunchEditorProcess(executablePath, processInfo)) { - PrintFailure("failed to launch XCUIEditorApp"); + PrintFailure("failed to launch XCEditor"); return 1; } diff --git a/tests/UI/Editor/unit/CMakeLists.txt b/tests/UI/Editor/unit/CMakeLists.txt index 43c473fa..93b873ff 100644 --- a/tests/UI/Editor/unit/CMakeLists.txt +++ b/tests/UI/Editor/unit/CMakeLists.txt @@ -68,7 +68,7 @@ add_executable(editor_ui_tests ${EDITOR_UI_UNIT_TEST_SOURCES}) target_link_libraries(editor_ui_tests PRIVATE - XCUIEditorLib + XCUIEditor GTest::gtest_main ) @@ -104,7 +104,7 @@ add_executable(editor_windowing_phase1_tests target_link_libraries(editor_windowing_phase1_tests PRIVATE - XCUIEditorLib + XCUIEditor GTest::gtest_main ) @@ -132,79 +132,3 @@ endif() gtest_discover_tests(editor_windowing_phase1_tests DISCOVERY_MODE POST_BUILD ) - -if(TARGET XCUIEditorAppLib) - set(EDITOR_APP_FEATURE_TEST_SOURCES - test_editor_project_runtime.cpp - test_project_browser_model.cpp - test_project_panel.cpp - test_hierarchy_scene_binding.cpp - test_scene_viewport_render_plan.cpp - test_scene_viewport_runtime.cpp - ) - - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test_inspector_presentation.cpp") - list(APPEND EDITOR_APP_FEATURE_TEST_SOURCES - test_inspector_presentation.cpp - ) - endif() - - list(APPEND EDITOR_APP_FEATURE_TEST_SOURCES - test_input_modifier_tracker.cpp - test_editor_host_command_bridge.cpp - test_editor_shell_asset_validation.cpp - test_editor_window_tab_drag_drop_target.cpp - test_editor_window_workspace_store.cpp - test_structured_editor_shell.cpp - test_editor_window_input_routing.cpp - test_ui_editor_panel_registry.cpp - test_viewport_object_id_picker.cpp - ) - - add_executable(editor_app_feature_tests - ${EDITOR_APP_FEATURE_TEST_SOURCES} - ) - - target_link_libraries(editor_app_feature_tests - PRIVATE - XCUIEditorAppLib - XCUIEditorAppCore - XCUIEditorLib - XCUIEditorHost - GTest::gtest_main - ) - - target_include_directories(editor_app_feature_tests - PRIVATE - ${XCENGINE_EDITOR_UI_TESTS_EDITOR_ROOT}/include - ${XCENGINE_EDITOR_UI_TESTS_EDITOR_ROOT} - ${CMAKE_SOURCE_DIR}/engine/include - ) - - if(MSVC) - target_compile_options(editor_app_feature_tests PRIVATE /utf-8 /FS) - set_target_properties(editor_app_feature_tests PROPERTIES - MSVC_DEBUG_INFORMATION_FORMAT "$<$:Embedded>" - COMPILE_PDB_NAME "editor_app_feature_tests-compile" - COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb" - COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/Debug" - COMPILE_PDB_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/Release" - COMPILE_PDB_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/MinSizeRel" - COMPILE_PDB_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/RelWithDebInfo" - ) - set_property(TARGET editor_app_feature_tests PROPERTY - MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") - endif() - - if(WIN32 AND EXISTS "${CMAKE_SOURCE_DIR}/engine/third_party/assimp/bin/assimp-vc143-mt.dll") - add_custom_command(TARGET editor_app_feature_tests POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_SOURCE_DIR}/engine/third_party/assimp/bin/assimp-vc143-mt.dll - $/assimp-vc143-mt.dll - ) - endif() - - gtest_discover_tests(editor_app_feature_tests - DISCOVERY_MODE POST_BUILD - ) -endif() diff --git a/tests/scripting/test_mono_script_runtime.cpp b/tests/scripting/test_mono_script_runtime.cpp index 64ef5de0..e66259e1 100644 --- a/tests/scripting/test_mono_script_runtime.cpp +++ b/tests/scripting/test_mono_script_runtime.cpp @@ -1423,6 +1423,9 @@ TEST_F( bool hasPublicContextRecordScene = false; bool hasPublicContextRecordScenePhase = false; bool hasPublicContextRecordSceneInjectionPoint = false; + bool hasPublicContextDrawRenderersByType = false; + bool hasPublicContextDrawRenderersByDesc = false; + bool hasPublicContextDrawRenderersByDescAndSettings = false; bool hasPublicContextRecordOpaqueScenePhase = false; bool hasPublicContextRecordBeforeOpaqueInjection = false; bool hasPublicContextRecordShaderVectorFullscreenPass = false; @@ -1468,6 +1471,7 @@ TEST_F( bool hasRenderGraphRasterPassBuilderCommit = false; bool hasRenderGraphRasterContextType = false; bool hasRenderGraphRasterContextCommandBuffer = false; + bool hasSceneRenderPhaseType = false; bool hasSceneRenderInjectionPointType = false; bool hasRenderPassProtectedRecordColorScaleFullscreenPass = false; bool hasRenderPassProtectedRecordShaderVectorFullscreenPass = false; @@ -1485,6 +1489,18 @@ TEST_F( selectionScript, "HasPublicContextRecordSceneInjectionPoint", hasPublicContextRecordSceneInjectionPoint)); + EXPECT_TRUE(runtime->TryGetFieldValue( + selectionScript, + "HasPublicContextDrawRenderersByType", + hasPublicContextDrawRenderersByType)); + EXPECT_TRUE(runtime->TryGetFieldValue( + selectionScript, + "HasPublicContextDrawRenderersByDesc", + hasPublicContextDrawRenderersByDesc)); + EXPECT_TRUE(runtime->TryGetFieldValue( + selectionScript, + "HasPublicContextDrawRenderersByDescAndSettings", + hasPublicContextDrawRenderersByDescAndSettings)); EXPECT_TRUE(runtime->TryGetFieldValue( selectionScript, "HasPublicContextRecordOpaqueScenePhase", @@ -1665,6 +1681,10 @@ TEST_F( selectionScript, "HasRenderGraphRasterContextCommandBuffer", hasRenderGraphRasterContextCommandBuffer)); + EXPECT_TRUE(runtime->TryGetFieldValue( + selectionScript, + "HasSceneRenderPhaseType", + hasSceneRenderPhaseType)); EXPECT_TRUE(runtime->TryGetFieldValue( selectionScript, "HasSceneRenderInjectionPointType", @@ -1685,6 +1705,9 @@ TEST_F( EXPECT_FALSE(hasPublicContextRecordScene); EXPECT_FALSE(hasPublicContextRecordScenePhase); EXPECT_FALSE(hasPublicContextRecordSceneInjectionPoint); + EXPECT_TRUE(hasPublicContextDrawRenderersByType); + EXPECT_TRUE(hasPublicContextDrawRenderersByDesc); + EXPECT_TRUE(hasPublicContextDrawRenderersByDescAndSettings); EXPECT_FALSE(hasPublicContextRecordOpaqueScenePhase); EXPECT_FALSE(hasPublicContextRecordBeforeOpaqueInjection); EXPECT_FALSE(hasPublicContextRecordShaderVectorFullscreenPass); @@ -1730,6 +1753,7 @@ TEST_F( EXPECT_TRUE(hasRenderGraphRasterPassBuilderCommit); EXPECT_TRUE(hasRenderGraphRasterContextType); EXPECT_TRUE(hasRenderGraphRasterContextCommandBuffer); + EXPECT_FALSE(hasSceneRenderPhaseType); EXPECT_FALSE(hasSceneRenderInjectionPointType); EXPECT_FALSE(hasRenderPassProtectedRecordColorScaleFullscreenPass); EXPECT_FALSE(hasRenderPassProtectedRecordShaderVectorFullscreenPass);