#include "Windowing/Frame/EditorWindowFrameOrchestrator.h" #include "Composition/EditorContext.h" #include "Composition/EditorShellRuntime.h" #include "Composition/EditorShellVariant.h" #include "Windowing/EditorWindowShared.h" #include #include #include #include namespace XCEngine::UI::Editor::App { using ::XCEngine::UI::UIDrawData; using ::XCEngine::UI::UIDrawList; using ::XCEngine::UI::UIInputEvent; using ::XCEngine::UI::UIInputEventType; using ::XCEngine::UI::UIPoint; namespace { bool IsVerboseRuntimeTraceEnabled() { static const bool s_enabled = IsEditorWindowVerboseRuntimeTraceEnabled(); return s_enabled; } std::string DescribeInputEventType(const UIInputEvent& event) { switch (event.type) { case UIInputEventType::PointerMove: return "PointerMove"; case UIInputEventType::PointerEnter: return "PointerEnter"; case UIInputEventType::PointerLeave: return "PointerLeave"; case UIInputEventType::PointerButtonDown: return "PointerDown"; case UIInputEventType::PointerButtonUp: return "PointerUp"; case UIInputEventType::PointerWheel: return "PointerWheel"; case UIInputEventType::KeyDown: return "KeyDown"; case UIInputEventType::KeyUp: return "KeyUp"; case UIInputEventType::Character: return "Character"; case UIInputEventType::FocusGained: return "FocusGained"; case UIInputEventType::FocusLost: return "FocusLost"; default: return "Unknown"; } } } // namespace EditorWindowFrameTransferRequests EditorWindowFrameOrchestrator::UpdateAndAppend( EditorContext& editorContext, UIEditorWorkspaceController& workspaceController, EditorShellRuntime& shellRuntime, const ::XCEngine::UI::UIRect& workspaceBounds, const std::vector& frameEvents, const std::optional& cursorScreenPoint, std::string_view captureStatusText, bool primary, bool globalTabDragActive, bool useDetachedTitleBarTabStrip, UIDrawData& drawData) const { LogInputTrace( editorContext, workspaceController, shellRuntime.GetShellInteractionState(), frameEvents); shellRuntime.Update( editorContext, workspaceController, workspaceBounds, frameEvents, captureStatusText, primary ? EditorShellVariant::Primary : EditorShellVariant::DetachedWindow, useDetachedTitleBarTabStrip, useDetachedTitleBarTabStrip ? kBorderlessTitleBarHeightDips : 0.0f, primary ? 0.0f : kBorderlessTitleBarHeightDips); const UIEditorShellInteractionFrame& shellFrame = shellRuntime.GetShellFrame(); const UIEditorDockHostInteractionState& dockHostInteractionState = shellRuntime.GetShellInteractionState().workspaceInteractionState.dockHostInteractionState; LogFrameInteractionTrace(workspaceController, frameEvents, shellFrame); EditorWindowFrameTransferRequests transferRequests = BuildShellTransferRequests( globalTabDragActive, cursorScreenPoint, dockHostInteractionState, shellFrame); if (const std::optional requestedKind = editorContext.ConsumeOpenUtilityWindowRequest(); requestedKind.has_value()) { transferRequests.utility.openUtilityWindow = EditorWindowOpenUtilityWindowRequest{ .kind = *requestedKind, .useCursorPlacement = cursorScreenPoint.has_value(), }; if (transferRequests.utility.openUtilityWindow->useCursorPlacement) { transferRequests.utility.openUtilityWindow->screenPoint = *cursorScreenPoint; } } for (const WorkspaceTraceEntry& entry : shellRuntime.GetTraceEntries()) { AppendUIEditorRuntimeTrace(entry.channel, entry.message); } shellRuntime.Append(drawData); return transferRequests; } void EditorWindowFrameOrchestrator::AppendInvalidFrame( EditorContext& editorContext, UIDrawList& drawList) const { 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); } std::string EditorWindowFrameOrchestrator::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(); } void EditorWindowFrameOrchestrator::LogInputTrace( EditorContext& editorContext, const UIEditorWorkspaceController& workspaceController, const UIEditorShellInteractionState& shellInteractionState, const std::vector& frameEvents) const { if (frameEvents.empty() || !IsVerboseRuntimeTraceEnabled()) { return; } AppendUIEditorRuntimeTrace( "input", DescribeInputEvents(frameEvents) + " | " + editorContext.DescribeWorkspaceState( workspaceController, shellInteractionState)); } void EditorWindowFrameOrchestrator::LogFrameInteractionTrace( const UIEditorWorkspaceController& workspaceController, 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=" << workspaceController.GetWorkspace().activePanelId << " message=" << shellFrame.result.workspaceResult.dockHostResult.layoutResult.message; AppendUIEditorRuntimeTrace("frame", frameTrace.str()); } EditorWindowFrameTransferRequests EditorWindowFrameOrchestrator::BuildShellTransferRequests( bool globalTabDragActive, const std::optional& cursorScreenPoint, const UIEditorDockHostInteractionState& dockHostInteractionState, const UIEditorShellInteractionFrame& shellFrame) const { EditorWindowFrameTransferRequests transferRequests = {}; if (!cursorScreenPoint.has_value()) { return transferRequests; } if (!globalTabDragActive && !dockHostInteractionState.activeTabDragNodeId.empty() && !dockHostInteractionState.activeTabDragPanelId.empty()) { transferRequests.workspace.beginGlobalTabDrag = EditorWindowPanelTransferRequest{ dockHostInteractionState.activeTabDragNodeId, dockHostInteractionState.activeTabDragPanelId, *cursorScreenPoint, }; } if (shellFrame.result.workspaceResult.dockHostResult.detachRequested) { transferRequests.workspace.detachPanel = EditorWindowPanelTransferRequest{ shellFrame.result.workspaceResult.dockHostResult.detachedNodeId, shellFrame.result.workspaceResult.dockHostResult.detachedPanelId, *cursorScreenPoint, }; } return transferRequests; } } // namespace XCEngine::UI::Editor::App