#include "Windowing/Content/EditorWorkspaceWindowContentController.h" #include "Windowing/System/EditorWindowPresentationPolicy.h" #include "Windowing/System/EditorWindowSystem.h" #include #include #include namespace XCEngine::UI::Editor::App { namespace { UIEditorWindowWorkspaceState BuildWindowStateFromController( std::string_view windowId, const UIEditorWorkspaceController& workspaceController) { UIEditorWindowWorkspaceState windowState = {}; windowState.windowId = std::string(windowId); windowState.workspace = workspaceController.GetWorkspace(); windowState.session = workspaceController.GetSession(); return windowState; } EditorWindowContentCursorKind ToContentCursorKind(ProjectPanel::CursorKind cursorKind) { switch (cursorKind) { case ProjectPanel::CursorKind::ResizeEW: return EditorWindowContentCursorKind::ResizeEW; case ProjectPanel::CursorKind::Arrow: default: return EditorWindowContentCursorKind::Arrow; } } EditorWindowContentCursorKind ToContentCursorKind( Widgets::UIEditorDockHostCursorKind cursorKind) { switch (cursorKind) { case Widgets::UIEditorDockHostCursorKind::ResizeEW: return EditorWindowContentCursorKind::ResizeEW; case Widgets::UIEditorDockHostCursorKind::ResizeNS: return EditorWindowContentCursorKind::ResizeNS; case Widgets::UIEditorDockHostCursorKind::Arrow: default: return EditorWindowContentCursorKind::Arrow; } } EditorWorkspaceWindowProjection BuildWorkspaceProjectionFromController( const UIEditorWorkspaceController& workspaceController) { EditorWorkspaceWindowProjection projection = {}; projection.minimumOuterSize = ResolveUIEditorDetachedWorkspaceMinimumOuterSize( workspaceController); projection.useDetachedTitleBarTabStrip = HasUIEditorSingleVisibleRootTab(workspaceController); projection.tabStripTitleText = ResolveUIEditorDetachedWorkspaceTitle(workspaceController); projection.detachedWindowTitleText = ResolveUIEditorDetachedWorkspaceTitle(workspaceController); return projection; } } // namespace EditorWorkspaceWindowContentController::EditorWorkspaceWindowContentController( std::string windowId, UIEditorWorkspaceController workspaceController, EditorWindowSystem& windowSystem) : m_windowId(std::move(windowId)), m_windowSystem(windowSystem) { RefreshProjectionFromWorkspaceController(workspaceController); } EditorWorkspaceWindowContentController::~EditorWorkspaceWindowContentController() = default; EditorWindowContentCapabilities EditorWorkspaceWindowContentController::GetCapabilities() const { return EditorWindowContentCapabilities{ .workspace = true, .dockHost = true, .inputFeedback = true, .titleBar = true, .viewportRendering = true, .utilityPanel = false, }; } EditorWindowWorkspaceBinding* EditorWorkspaceWindowContentController::TryGetWorkspaceBinding() { return this; } const EditorWindowWorkspaceBinding* EditorWorkspaceWindowContentController::TryGetWorkspaceBinding() const { return this; } EditorWindowDockHostBinding* EditorWorkspaceWindowContentController::TryGetDockHostBinding() { return this; } const EditorWindowDockHostBinding* EditorWorkspaceWindowContentController::TryGetDockHostBinding() const { return this; } const EditorWindowInputFeedbackBinding* EditorWorkspaceWindowContentController::TryGetInputFeedbackBinding() const { return this; } const EditorWindowTitleBarBinding* EditorWorkspaceWindowContentController::TryGetTitleBarBinding() const { return this; } const EditorWorkspaceWindowProjection* EditorWorkspaceWindowContentController::TryGetWorkspaceProjection() const { return &m_projection; } void EditorWorkspaceWindowContentController::RefreshWorkspaceProjection( EditorWorkspaceWindowProjection projection) { m_projection = std::move(projection); } bool EditorWorkspaceWindowContentController::TryBuildAuthoritativeWorkspaceController( UIEditorWorkspaceController& outController) const { const UIEditorWindowWorkspaceState* windowState = m_windowSystem.FindWindowState(m_windowId); if (windowState == nullptr) { return false; } outController = BuildWorkspaceControllerForWindowState( m_windowSystem.GetPanelRegistry(), *windowState); return true; } void EditorWorkspaceWindowContentController::RefreshProjectionFromWorkspaceController( const UIEditorWorkspaceController& workspaceController, bool primary) { const std::wstring preservedWindowTitle = m_projection.windowTitle; m_projection = BuildWorkspaceProjectionFromController(workspaceController); if (!primary) { m_projection.windowTitle = ResolveEditorWindowPresentationTitle( std::wstring_view{}, workspaceController.GetPanelRegistry(), BuildWindowStateFromController(m_windowId, workspaceController), false); } else if (!preservedWindowTitle.empty()) { m_projection.windowTitle = preservedWindowTitle; } } void EditorWorkspaceWindowContentController::Initialize( const EditorWindowContentInitializationContext& context) { m_shellRuntime.Initialize(context.repoRoot, context.textureHost, context.textMeasurer); m_shellRuntime.AttachViewportWindowRenderer(context.viewportRenderer); } void EditorWorkspaceWindowContentController::Shutdown() { m_shellRuntime.Shutdown(); } void EditorWorkspaceWindowContentController::ResetInteractionState() { m_shellRuntime.ResetInteractionState(); } void EditorWorkspaceWindowContentController::SetViewportSurfacePresentationEnabled(bool enabled) { m_shellRuntime.SetViewportSurfacePresentationEnabled(enabled); } EditorWindowFrameTransferRequests EditorWorkspaceWindowContentController::UpdateAndAppend( const EditorWindowContentFrameContext& context, ::XCEngine::UI::UIDrawData& drawData) { UIEditorWorkspaceController workspaceController = {}; if (!TryBuildAuthoritativeWorkspaceController(workspaceController)) { AppendUIEditorRuntimeTrace( "window", "workspace frame skipped: authoritative state missing for window '" + m_windowId + "'"); return {}; } const auto beforeSnapshot = BuildUIEditorWorkspaceLayoutSnapshot( workspaceController.GetWorkspace(), workspaceController.GetSession()); EditorWindowFrameTransferRequests transferRequests = m_frameOrchestrator.UpdateAndAppend( context.editorContext, workspaceController, m_shellRuntime, context.bounds, context.inputEvents, context.cursorScreenPoint, context.captureStatusText, context.primary, context.globalTabDragActive, context.useDetachedTitleBarTabStrip, drawData); const auto afterSnapshot = BuildUIEditorWorkspaceLayoutSnapshot( workspaceController.GetWorkspace(), workspaceController.GetSession()); if (!AreUIEditorWorkspaceLayoutSnapshotsEquivalent(beforeSnapshot, afterSnapshot)) { std::string error = {}; if (!m_windowSystem.CommitLiveWindowMutation( m_windowId, workspaceController, error)) { AppendUIEditorRuntimeTrace( "window", "workspace direct commit rejected for window '" + m_windowId + "': " + error); } else { RefreshProjectionFromWorkspaceController(workspaceController, context.primary); } } return transferRequests; } void EditorWorkspaceWindowContentController::RenderRequestedViewports( const ::XCEngine::Rendering::RenderContext& renderContext) { m_shellRuntime.RenderRequestedViewports(renderContext); } const UIEditorShellInteractionFrame& EditorWorkspaceWindowContentController::GetShellFrame() const { return m_shellRuntime.GetShellFrame(); } const UIEditorShellInteractionState& EditorWorkspaceWindowContentController::GetShellInteractionState() const { return m_shellRuntime.GetShellInteractionState(); } void EditorWorkspaceWindowContentController::SetExternalDockHostDropPreview( const Widgets::UIEditorDockHostDropPreviewState& preview) { m_shellRuntime.SetExternalDockHostDropPreview(preview); } void EditorWorkspaceWindowContentController::ClearExternalDockHostDropPreview() { m_shellRuntime.ClearExternalDockHostDropPreview(); } bool EditorWorkspaceWindowContentController::TryResolveDockTabDragHotspot( std::string_view nodeId, std::string_view panelId, const ::XCEngine::UI::UIPoint& point, ::XCEngine::UI::UIPoint& outHotspot) const { return m_shellRuntime.TryResolveDockTabDragHotspot( nodeId, panelId, point, outHotspot); } UIEditorDockHostTabDropTarget EditorWorkspaceWindowContentController::ResolveDockTabDropTarget( const ::XCEngine::UI::UIPoint& point) const { return m_shellRuntime.ResolveDockTabDropTarget(point); } bool EditorWorkspaceWindowContentController::HasHostedContentCapture() const { return m_shellRuntime.HasHostedContentCapture(); } bool EditorWorkspaceWindowContentController::HasShellInteractiveCapture() const { return m_shellRuntime.HasShellInteractiveCapture(); } bool EditorWorkspaceWindowContentController::HasInteractiveCapture() const { return m_shellRuntime.HasInteractiveCapture(); } EditorWindowContentCursorKind EditorWorkspaceWindowContentController::GetHostedContentCursorKind() const { return ToContentCursorKind(m_shellRuntime.GetHostedContentCursorKind()); } EditorWindowContentCursorKind EditorWorkspaceWindowContentController::GetDockCursorKind() const { return ToContentCursorKind(m_shellRuntime.GetDockCursorKind()); } ::XCEngine::UI::UISize EditorWorkspaceWindowContentController::ResolveMinimumOuterSize() const { return m_projection.minimumOuterSize; } bool EditorWorkspaceWindowContentController::ShouldUseDetachedTitleBarTabStrip() const { return m_projection.useDetachedTitleBarTabStrip; } std::string EditorWorkspaceWindowContentController::ResolveTabStripTitleText( std::string_view fallbackTitle) const { return m_projection.tabStripTitleText.empty() ? std::string(fallbackTitle) : m_projection.tabStripTitleText; } std::string EditorWorkspaceWindowContentController::ResolveDetachedWindowTitleText( std::string_view fallbackWindowTitle) const { return m_projection.detachedWindowTitleText.empty() ? std::string(fallbackWindowTitle) : m_projection.detachedWindowTitleText; } std::unique_ptr CreateEditorWorkspaceWindowContentController( std::string_view windowId, UIEditorWorkspaceController workspaceController, EditorWindowSystem& windowSystem) { return std::make_unique( std::string(windowId), std::move(workspaceController), windowSystem); } } // namespace XCEngine::UI::Editor::App