refactor(new_editor): extract window content boundary

This commit is contained in:
2026-04-22 20:32:56 +08:00
parent 6efbaf450e
commit e251b77d0d
19 changed files with 1223 additions and 234 deletions

View File

@@ -1,6 +1,7 @@
#include "Platform/Win32/EditorWindow.h"
#include "Bootstrap/EditorResources.h"
#include "Platform/Win32/EditorWindowChromeController.h"
#include "Platform/Win32/EditorWindowContentController.h"
#include "Platform/Win32/EditorWindowSupport.h"
#include "Platform/Win32/EditorWindowFrameOrchestrator.h"
#include "Platform/Win32/EditorWindowInputController.h"
@@ -9,6 +10,7 @@
#include "Composition/EditorContext.h"
#include <XCEditor/Docking/UIEditorDockHostTransfer.h>
#include <XCEditor/Foundation/UIEditorRuntimeTrace.h>
#include <XCEditor/Shell/UIEditorShellInteraction.h>
#include <XCEngine/UI/Types.h>
#include <algorithm>
#include <sstream>
@@ -74,13 +76,13 @@ EditorWindow::EditorWindow(
std::string windowId,
std::wstring title,
bool primary,
UIEditorWorkspaceController workspaceController)
std::unique_ptr<EditorWindowContentController> contentController)
: m_state(std::make_unique<EditorWindowState>())
, m_chromeController(std::make_unique<EditorWindowChromeController>())
, m_frameOrchestrator(std::make_unique<EditorWindowFrameOrchestrator>())
, m_inputController(std::make_unique<EditorWindowInputController>())
, m_runtime(std::make_unique<EditorWindowRuntimeController>(
std::move(workspaceController))) {
std::move(contentController))) {
m_state->window.windowId = std::move(windowId);
m_state->window.title = std::move(title);
m_state->window.primary = primary;
@@ -126,6 +128,10 @@ const std::wstring& EditorWindow::GetTitle() const {
return m_state->window.title;
}
const UIEditorWorkspaceController* EditorWindow::TryGetWorkspaceController() const {
return m_runtime->TryGetWorkspaceController();
}
const UIEditorWorkspaceController& EditorWindow::GetWorkspaceController() const {
return m_runtime->GetWorkspaceController();
}
@@ -134,20 +140,12 @@ UIEditorWorkspaceController& EditorWindow::GetMutableWorkspaceController() {
return m_runtime->GetMutableWorkspaceController();
}
const EditorShellRuntime& EditorWindow::GetShellRuntime() const {
return m_runtime->GetShellRuntime();
bool EditorWindow::HasHostedContentCapture() const {
return m_runtime->HasHostedContentCapture();
}
EditorShellRuntime& EditorWindow::GetShellRuntime() {
return m_runtime->GetShellRuntime();
}
const UIEditorShellInteractionFrame& EditorWindow::GetShellFrame() const {
return m_runtime->GetShellFrame();
}
const UIEditorShellInteractionState& EditorWindow::GetShellInteractionState() const {
return m_runtime->GetShellInteractionState();
bool EditorWindow::HasShellInteractiveCapture() const {
return m_runtime->HasShellInteractiveCapture();
}
void EditorWindow::SetExternalDockHostDropPreview(
@@ -221,16 +219,12 @@ bool EditorWindow::Initialize(
<< " scale=" << GetDpiScale();
LogRuntimeTrace("window", dpiTrace.str());
const bool initialized = m_runtime->Initialize(
return m_runtime->Initialize(
m_state->window.hwnd,
repoRoot,
editorContext,
captureRoot,
autoCaptureOnStartup);
if (initialized) {
RequestFrame(EditorWindowFrameRequestReason::Initial);
}
return initialized;
}
void EditorWindow::Shutdown() {
@@ -345,7 +339,7 @@ bool EditorWindow::TryResolveDockTabDragHotspot(
POINT& outHotspot) const {
const UIPoint clientPointDips = ConvertScreenPixelsToClientDips(screenPoint);
UIPoint hotspotDips = {};
if (!m_runtime->GetShellRuntime().TryResolveDockTabDragHotspot(
if (!m_runtime->TryResolveDockTabDragHotspot(
nodeId,
panelId,
clientPointDips,
@@ -363,7 +357,7 @@ bool EditorWindow::TryResolveDockTabDragHotspot(
bool EditorWindow::TryResolveDockTabDropTarget(
const POINT& screenPoint,
UIEditorDockHostTabDropTarget& outTarget) const {
outTarget = m_runtime->GetShellRuntime().ResolveDockTabDropTarget(
outTarget = m_runtime->ResolveDockTabDropTarget(
ConvertScreenPixelsToClientDips(screenPoint));
return outTarget.valid;
}
@@ -388,7 +382,6 @@ void EditorWindow::OnResize(UINT width, UINT height) {
if (!matchesPredictedClientSize) {
ApplyWindowResize(width, height);
}
RequestFrame(EditorWindowFrameRequestReason::Resize);
}
void EditorWindow::OnEnterSizeMove() {
@@ -403,7 +396,6 @@ void EditorWindow::OnExitSizeMove() {
if (QueryCurrentClientPixelSize(width, height)) {
ApplyWindowResize(width, height);
}
RequestFrame(EditorWindowFrameRequestReason::ExitSizeMove);
}
void EditorWindow::OnDpiChanged(UINT dpi, const RECT& suggestedRect) {
@@ -432,7 +424,6 @@ void EditorWindow::OnDpiChanged(UINT dpi, const RECT& suggestedRect) {
trace << "dpi changed to " << m_chromeController->GetWindowDpi()
<< " scale=" << GetDpiScale();
LogRuntimeTrace("window", trace.str());
RequestFrame(EditorWindowFrameRequestReason::DpiChanged);
}
bool EditorWindow::IsVerboseRuntimeTraceEnabled() {
@@ -592,9 +583,8 @@ std::uint8_t ButtonMaskFromModifiers(const UIInputModifiers& modifiers) {
}
std::uint8_t ResolveExpectedShellCaptureButtons(
const EditorShellRuntime& shellRuntime) {
const UIEditorShellInteractionState& shellState) {
std::uint8_t expectedButtons = 0u;
const auto& shellState = shellRuntime.GetShellInteractionState();
const auto& dockHostState =
shellState.workspaceInteractionState.dockHostInteractionState;
if (dockHostState.splitterDragState.active ||
@@ -657,15 +647,19 @@ EditorWindowFrameTransferRequests EditorWindow::RenderFrame(
return transferRequests;
}
void EditorWindow::OnPaintMessage() {
EditorWindowFrameTransferRequests EditorWindow::OnPaintMessage(
EditorContext& editorContext,
bool globalTabDragActive) {
if (!m_runtime->IsReady() || m_state->window.hwnd == nullptr) {
return;
return {};
}
PAINTSTRUCT paintStruct = {};
BeginPaint(m_state->window.hwnd, &paintStruct);
const EditorWindowFrameTransferRequests transferRequests =
RenderFrame(editorContext, globalTabDragActive);
EndPaint(m_state->window.hwnd, &paintStruct);
RequestFrame(EditorWindowFrameRequestReason::PaintMessage);
return transferRequests;
}
UIRect EditorWindow::ResolveWorkspaceBounds(float clientWidthDips, float clientHeightDips) const {
@@ -693,17 +687,27 @@ EditorWindowFrameTransferRequests EditorWindow::RenderRuntimeFrame(
SyncShellCapturedPointerButtonsFromSystemState();
std::vector<UIInputEvent> frameEvents = m_inputController->TakePendingEvents();
const bool useDetachedTitleBarTabStrip = ShouldUseDetachedTitleBarTabStrip();
editorContext.AttachTextMeasurer(m_runtime->GetTextMeasurer());
const Host::D3D12WindowRenderLoopFrameContext frameContext = m_runtime->BeginFrame();
if (!frameContext.warning.empty()) {
LogRuntimeTrace("viewport", frameContext.warning);
}
const EditorWindowFrameTransferRequests transferRequests =
m_frameOrchestrator->UpdateAndAppend(
editorContext,
*m_runtime,
workspaceBounds,
frameEvents,
m_runtime->BuildCaptureStatusText(),
m_state->window.primary,
globalTabDragActive,
useDetachedTitleBarTabStrip,
m_runtime->UpdateAndAppend(
EditorWindowContentFrameContext{
.editorContext = editorContext,
.bounds = workspaceBounds,
.inputEvents = frameEvents,
.captureStatusText = m_runtime->BuildCaptureStatusText(),
.primary = m_state->window.primary,
.globalTabDragActive = globalTabDragActive,
.useDetachedTitleBarTabStrip = useDetachedTitleBarTabStrip,
},
drawData);
if (frameContext.canRenderViewports) {
m_runtime->RenderRequestedViewports(frameContext.renderContext);
}
ApplyShellRuntimePointerCapture();
ApplyCurrentCursor();
@@ -714,7 +718,7 @@ void EditorWindow::SyncShellCapturedPointerButtonsFromSystemState() {
m_inputController->SyncInputModifiersFromSystemState();
const std::uint8_t expectedButtons = ResolveExpectedShellCaptureButtons(
m_runtime->GetShellRuntime());
m_runtime->GetShellInteractionState());
if (expectedButtons == 0u ||
m_inputController->HasPendingPointerStateReconciliationEvent()) {
return;
@@ -729,12 +733,12 @@ void EditorWindow::SyncShellCapturedPointerButtonsFromSystemState() {
}
void EditorWindow::ApplyShellRuntimePointerCapture() {
if (m_runtime->GetShellRuntime().HasShellInteractiveCapture()) {
if (m_runtime->HasShellInteractiveCapture()) {
AcquirePointerCapture(EditorWindowPointerCaptureOwner::Shell);
return;
}
if (m_runtime->GetShellRuntime().HasHostedContentCapture()) {
if (m_runtime->HasHostedContentCapture()) {
AcquirePointerCapture(EditorWindowPointerCaptureOwner::HostedContent);
return;
}
@@ -794,7 +798,7 @@ bool EditorWindow::ApplyCurrentCursor() const {
bool EditorWindow::HasInteractiveCaptureState() const {
return m_runtime->GetShellRuntime().HasInteractiveCapture() ||
return m_runtime->HasInteractiveCapture() ||
m_chromeController->IsBorderlessWindowDragRestoreArmed() ||
m_chromeController->IsBorderlessResizeActive() ||
m_inputController->HasPointerCaptureOwner();
@@ -927,17 +931,6 @@ void EditorWindow::ResetInputModifiers() {
void EditorWindow::RequestManualScreenshot() {
m_runtime->RequestManualScreenshot("manual_f12");
RequestFrame(EditorWindowFrameRequestReason::ManualScreenshot);
}
void EditorWindow::RequestFrame(EditorWindowFrameRequestReason reason) {
m_pendingFrameRequestReasons |= ToFrameRequestMask(reason);
}
std::uint32_t EditorWindow::ConsumePendingFrameRequestReasons() {
const std::uint32_t pendingFrameRequestReasons = m_pendingFrameRequestReasons;
m_pendingFrameRequestReasons = 0u;
return pendingFrameRequestReasons;
}
bool EditorWindow::IsPointerInsideClientArea() const {
@@ -969,20 +962,22 @@ LPCWSTR EditorWindow::ResolveCurrentCursorResource() const {
return Host::ResolveBorderlessWindowResizeCursor(borderlessResizeEdge);
}
switch (m_runtime->GetShellRuntime().GetHostedContentCursorKind()) {
case ProjectPanel::CursorKind::ResizeEW:
switch (m_runtime->GetHostedContentCursorKind()) {
case EditorWindowContentCursorKind::ResizeEW:
return IDC_SIZEWE;
case ProjectPanel::CursorKind::Arrow:
case EditorWindowContentCursorKind::ResizeNS:
return IDC_SIZENS;
case EditorWindowContentCursorKind::Arrow:
default:
break;
}
switch (m_runtime->GetShellRuntime().GetDockCursorKind()) {
case Widgets::UIEditorDockHostCursorKind::ResizeEW:
switch (m_runtime->GetDockCursorKind()) {
case EditorWindowContentCursorKind::ResizeEW:
return IDC_SIZEWE;
case Widgets::UIEditorDockHostCursorKind::ResizeNS:
case EditorWindowContentCursorKind::ResizeNS:
return IDC_SIZENS;
case Widgets::UIEditorDockHostCursorKind::Arrow:
case EditorWindowContentCursorKind::Arrow:
default:
return IDC_ARROW;
}