#include "Platform/Win32/EditorWindow.h" #include "Platform/Win32/EditorWindowConstants.h" #include "Platform/Win32/EditorWindowInputInternal.h" #include "Platform/Win32/EditorWindowRuntimeInternal.h" #include "Platform/Win32/EditorWindowStyle.h" #include "State/EditorContext.h" #include #include namespace XCEngine::UI::Editor::App { using namespace EditorWindowInternal; using namespace EditorWindowInputInternal; using ::XCEngine::UI::UIDrawList; using ::XCEngine::UI::UIInputEvent; using ::XCEngine::UI::UIPoint; using ::XCEngine::UI::UIRect; EditorWindowFrameTransferRequests EditorWindow::RenderRuntimeFrame( EditorContext& editorContext, bool globalTabDragActive, const UIRect& workspaceBounds, UIDrawList& drawList) { 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); const bool useDetachedTitleBarTabStrip = ShouldUseDetachedTitleBarTabStrip(); m_composition.shellRuntime.Update( editorContext, m_composition.workspaceController, workspaceBounds, frameEvents, BuildCaptureStatusText(), m_window.primary ? EditorShellVariant::Primary : EditorShellVariant::DetachedWindow, useDetachedTitleBarTabStrip, useDetachedTitleBarTabStrip ? kBorderlessTitleBarHeightDips : 0.0f); const UIEditorShellInteractionFrame& shellFrame = m_composition.shellRuntime.GetShellFrame(); const UIEditorDockHostInteractionState& dockHostInteractionState = m_composition.shellRuntime .GetShellInteractionState() .workspaceInteractionState .dockHostInteractionState; LogFrameInteractionTrace(editorContext, frameEvents, shellFrame); const EditorWindowFrameTransferRequests transferRequests = BuildShellTransferRequests(globalTabDragActive, dockHostInteractionState, shellFrame); 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); } return transferRequests; } void EditorWindow::RenderInvalidFrame( EditorContext& editorContext, UIDrawList& drawList) const { drawList.AddText( UIPoint(28.0f, 28.0f), "Editor shell asset invalid.", EditorWindowInternal::kShellTextColor, 16.0f); drawList.AddText( UIPoint(28.0f, 54.0f), editorContext.GetValidationMessage().empty() ? std::string("Unknown validation error.") : editorContext.GetValidationMessage(), EditorWindowInternal::kShellMutedTextColor, 12.0f); } void EditorWindow::LogFrameInteractionTrace( EditorContext& editorContext, const std::vector& frameEvents, const UIEditorShellInteractionFrame& shellFrame) const { if (!IsVerboseRuntimeTraceEnabled() || (frameEvents.empty() && !shellFrame.result.workspaceResult.dockHostResult.layoutChanged && !shellFrame.result.workspaceResult.dockHostResult.commandExecuted)) { return; } 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()); } EditorWindowFrameTransferRequests EditorWindow::BuildShellTransferRequests( bool globalTabDragActive, const UIEditorDockHostInteractionState& dockHostInteractionState, const UIEditorShellInteractionFrame& shellFrame) const { EditorWindowFrameTransferRequests transferRequests = {}; POINT screenPoint = {}; const bool hasScreenPoint = GetCursorPos(&screenPoint) != FALSE; if (!globalTabDragActive && !dockHostInteractionState.activeTabDragNodeId.empty() && !dockHostInteractionState.activeTabDragPanelId.empty() && hasScreenPoint) { transferRequests.beginGlobalTabDrag = EditorWindowPanelTransferRequest{ dockHostInteractionState.activeTabDragNodeId, dockHostInteractionState.activeTabDragPanelId, screenPoint, }; } if (shellFrame.result.workspaceResult.dockHostResult.detachRequested && hasScreenPoint) { transferRequests.detachPanel = EditorWindowPanelTransferRequest{ shellFrame.result.workspaceResult.dockHostResult.detachedNodeId, shellFrame.result.workspaceResult.dockHostResult.detachedPanelId, screenPoint, }; } return transferRequests; } 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& 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(event.position.x) << ',' << static_cast(event.position.y); } stream << ']'; return stream.str(); } } // namespace XCEngine::UI::Editor::App