refactor(new_editor/app): reorganize host structure and add smoke test

This commit is contained in:
2026-04-15 08:24:06 +08:00
parent 3617b4840b
commit 9e5954cf0a
235 changed files with 11157 additions and 10028 deletions

View File

@@ -0,0 +1,235 @@
#include "Platform/Win32/EditorWindow.h"
#include "Platform/Win32/EditorWindowConstants.h"
#include "Platform/Win32/EditorWindowInputSupport.h"
#include "Platform/Win32/EditorWindowRuntimeSupport.h"
#include "Platform/Win32/EditorWindowStyle.h"
#include <XCEngine/UI/DrawData.h>
#include <algorithm>
#include <sstream>
namespace XCEngine::UI::Editor::App {
using namespace EditorWindowSupport;
using ::XCEngine::UI::UIDrawData;
using ::XCEngine::UI::UIDrawList;
using ::XCEngine::UI::UIInputEvent;
using ::XCEngine::UI::UIPoint;
using ::XCEngine::UI::UIRect;
void EditorWindow::RenderFrame(
EditorContext& editorContext,
bool globalTabDragActive) {
if (!m_render.ready || m_window.hwnd == nullptr) {
return;
}
UINT pixelWidth = 0u;
UINT pixelHeight = 0u;
if (!ResolveRenderClientPixelSize(pixelWidth, pixelHeight)) {
return;
}
const float width = PixelsToDips(static_cast<float>(pixelWidth));
const float height = PixelsToDips(static_cast<float>(pixelHeight));
const UIRect workspaceBounds = ResolveWorkspaceBounds(width, height);
UIDrawData drawData = {};
UIDrawList& drawList = drawData.EmplaceDrawList("XCEditorShell");
drawList.AddFilledRect(
UIRect(0.0f, 0.0f, width, height),
kShellSurfaceColor);
if (editorContext.IsValid()) {
std::vector<UIInputEvent> frameEvents = std::move(m_input.pendingEvents);
m_input.pendingEvents.clear();
if (!frameEvents.empty() && IsVerboseRuntimeTraceEnabled()) {
LogRuntimeTrace(
"input",
DescribeInputEvents(frameEvents) + " | " +
editorContext.DescribeWorkspaceState(
m_composition.workspaceController,
m_composition.shellRuntime.GetShellInteractionState()));
}
const Host::D3D12WindowRenderLoopFrameContext frameContext =
m_render.windowRenderLoop.BeginFrame();
if (!frameContext.warning.empty()) {
LogRuntimeTrace("viewport", frameContext.warning);
}
editorContext.AttachTextMeasurer(m_render.renderer);
m_composition.shellRuntime.Update(
editorContext,
m_composition.workspaceController,
workspaceBounds,
frameEvents,
BuildCaptureStatusText(),
m_window.primary
? EditorShellVariant::Primary
: EditorShellVariant::DetachedWindow);
const UIEditorShellInteractionFrame& shellFrame =
m_composition.shellRuntime.GetShellFrame();
const UIEditorDockHostInteractionState& dockHostInteractionState =
m_composition.shellRuntime
.GetShellInteractionState()
.workspaceInteractionState
.dockHostInteractionState;
if (IsVerboseRuntimeTraceEnabled() &&
(!frameEvents.empty() ||
shellFrame.result.workspaceResult.dockHostResult.layoutChanged ||
shellFrame.result.workspaceResult.dockHostResult.commandExecuted)) {
std::ostringstream frameTrace = {};
frameTrace << "result consumed="
<< (shellFrame.result.consumed ? "true" : "false")
<< " layoutChanged="
<< (shellFrame.result.workspaceResult.dockHostResult.layoutChanged ? "true" : "false")
<< " commandExecuted="
<< (shellFrame.result.workspaceResult.dockHostResult.commandExecuted ? "true" : "false")
<< " active="
<< m_composition.workspaceController.GetWorkspace().activePanelId
<< " message="
<< shellFrame.result.workspaceResult.dockHostResult.layoutResult.message;
LogRuntimeTrace("frame", frameTrace.str());
}
if (!globalTabDragActive &&
!dockHostInteractionState.activeTabDragNodeId.empty() &&
!dockHostInteractionState.activeTabDragPanelId.empty()) {
QueuePendingTabDragStart(
dockHostInteractionState.activeTabDragNodeId,
dockHostInteractionState.activeTabDragPanelId);
}
if (shellFrame.result.workspaceResult.dockHostResult.detachRequested) {
QueuePendingDetachRequest(
shellFrame.result.workspaceResult.dockHostResult.detachedNodeId,
shellFrame.result.workspaceResult.dockHostResult.detachedPanelId);
}
ApplyHostCaptureRequests(shellFrame.result);
for (const WorkspaceTraceEntry& entry : m_composition.shellRuntime.GetTraceEntries()) {
LogRuntimeTrace(entry.channel, entry.message);
}
ApplyHostedContentCaptureRequests();
ApplyCurrentCursor();
m_composition.shellRuntime.Append(drawList);
if (frameContext.canRenderViewports) {
m_composition.shellRuntime.RenderRequestedViewports(frameContext.renderContext);
}
} else {
drawList.AddText(
UIPoint(28.0f, 28.0f),
"Editor shell asset invalid.",
kShellTextColor,
16.0f);
drawList.AddText(
UIPoint(28.0f, 54.0f),
editorContext.GetValidationMessage().empty()
? std::string("Unknown validation error.")
: editorContext.GetValidationMessage(),
kShellMutedTextColor,
12.0f);
}
AppendBorderlessWindowChrome(drawList, width);
const Host::D3D12WindowRenderLoopPresentResult presentResult =
m_render.windowRenderLoop.Present(drawData);
if (!presentResult.warning.empty()) {
LogRuntimeTrace("present", presentResult.warning);
}
m_render.autoScreenshot.CaptureIfRequested(
m_render.renderer,
drawData,
pixelWidth,
pixelHeight,
presentResult.framePresented);
}
void EditorWindow::OnPaintMessage(
EditorContext& editorContext,
bool globalTabDragActive) {
if (!m_render.ready || m_window.hwnd == nullptr) {
return;
}
PAINTSTRUCT paintStruct = {};
BeginPaint(m_window.hwnd, &paintStruct);
RenderFrame(editorContext, globalTabDragActive);
EndPaint(m_window.hwnd, &paintStruct);
}
UIRect EditorWindow::ResolveWorkspaceBounds(float clientWidthDips, float clientHeightDips) const {
if (!IsBorderlessWindowEnabled()) {
return UIRect(0.0f, 0.0f, clientWidthDips, clientHeightDips);
}
const float titleBarHeight = (std::min)(kBorderlessTitleBarHeightDips, clientHeightDips);
return UIRect(
0.0f,
titleBarHeight,
clientWidthDips,
(std::max)(0.0f, clientHeightDips - titleBarHeight));
}
std::string EditorWindow::BuildCaptureStatusText() const {
if (m_render.autoScreenshot.HasPendingCapture()) {
return "Shot pending...";
}
if (!m_render.autoScreenshot.GetLastCaptureError().empty()) {
return TruncateText(m_render.autoScreenshot.GetLastCaptureError(), 38u);
}
if (!m_render.autoScreenshot.GetLastCaptureSummary().empty()) {
return TruncateText(m_render.autoScreenshot.GetLastCaptureSummary(), 38u);
}
return {};
}
void EditorWindow::ApplyHostCaptureRequests(const UIEditorShellInteractionResult& result) {
if (result.requestPointerCapture && GetCapture() != m_window.hwnd) {
SetCapture(m_window.hwnd);
}
if (result.releasePointerCapture && GetCapture() == m_window.hwnd) {
ReleaseCapture();
}
}
void EditorWindow::ApplyHostedContentCaptureRequests() {
if (m_composition.shellRuntime.WantsHostPointerCapture() &&
GetCapture() != m_window.hwnd) {
SetCapture(m_window.hwnd);
}
if (m_composition.shellRuntime.WantsHostPointerRelease() &&
GetCapture() == m_window.hwnd &&
!m_composition.shellRuntime.HasShellInteractiveCapture()) {
ReleaseCapture();
}
}
std::string EditorWindow::DescribeInputEvents(
const std::vector<UIInputEvent>& events) const {
std::ostringstream stream = {};
stream << "events=[";
for (std::size_t index = 0; index < events.size(); ++index) {
if (index > 0u) {
stream << " | ";
}
const UIInputEvent& event = events[index];
stream << DescribeInputEventType(event)
<< '@'
<< static_cast<int>(event.position.x)
<< ','
<< static_cast<int>(event.position.y);
}
stream << ']';
return stream.str();
}
} // namespace XCEngine::UI::Editor::App