#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 #include #include 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(pixelWidth)); const float height = PixelsToDips(static_cast(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 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)); } } // namespace XCEngine::UI::Editor::App