#include "Composition/EditorShellRuntimeInternal.h" #include "State/EditorContext.h" #include "Composition/EditorPanelIds.h" #include namespace XCEngine::UI::Editor::App::Internal { namespace { using ::XCEngine::UI::UIInputEvent; using ::XCEngine::UI::UIInputEventType; using Widgets::UIEditorDockHostHitTargetKind; bool IsPointerInputEventType(UIInputEventType type) { switch (type) { case UIInputEventType::PointerMove: case UIInputEventType::PointerEnter: case UIInputEventType::PointerLeave: case UIInputEventType::PointerButtonDown: case UIInputEventType::PointerButtonUp: case UIInputEventType::PointerWheel: return true; default: return false; } } } // namespace std::vector FilterShellInputEventsForHostedContentCapture( const std::vector& inputEvents) { std::vector filteredEvents = {}; filteredEvents.reserve(inputEvents.size()); for (const UIInputEvent& event : inputEvents) { switch (event.type) { case UIInputEventType::PointerMove: case UIInputEventType::PointerEnter: case UIInputEventType::PointerLeave: case UIInputEventType::PointerButtonDown: case UIInputEventType::PointerButtonUp: case UIInputEventType::PointerWheel: break; default: filteredEvents.push_back(event); break; } } return filteredEvents; } bool ShouldHostedContentYieldPointerStream( const UIEditorShellInteractionFrame& shellFrame, bool shellInteractiveCaptureActive) { if (shellInteractiveCaptureActive || shellFrame.result.requestPointerCapture || shellFrame.result.releasePointerCapture) { return true; } return shellFrame.result.workspaceResult.dockHostResult.hitTarget.kind == UIEditorDockHostHitTargetKind::SplitterHandle; } std::vector FilterHostedContentInputEventsForShellOwnership( const std::vector& inputEvents, bool shellOwnsPointerStream) { if (!shellOwnsPointerStream) { return inputEvents; } std::vector filteredEvents = {}; filteredEvents.reserve(inputEvents.size() + 1u); bool strippedPointerInput = false; UIInputEvent lastPointerEvent = {}; for (const UIInputEvent& event : inputEvents) { if (IsPointerInputEventType(event.type)) { strippedPointerInput = true; lastPointerEvent = event; continue; } filteredEvents.push_back(event); } if (strippedPointerInput) { UIInputEvent leaveEvent = {}; leaveEvent.type = UIInputEventType::PointerLeave; leaveEvent.position = lastPointerEvent.position; leaveEvent.modifiers = lastPointerEvent.modifiers; filteredEvents.push_back(leaveEvent); } return filteredEvents; } } // namespace XCEngine::UI::Editor::App::Internal namespace XCEngine::UI::Editor::App { using namespace Internal; void EditorShellRuntime::Update( EditorContext& context, UIEditorWorkspaceController& workspaceController, const ::XCEngine::UI::UIRect& bounds, const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents, std::string_view captureText, EditorShellVariant shellVariant, bool useDetachedTitleBarTabStrip, float detachedTitleBarTabHeight) { UIEditorShellInteractionMetrics metrics = ResolveUIEditorShellInteractionMetrics(); if (useDetachedTitleBarTabStrip && detachedTitleBarTabHeight > 0.0f) { metrics.shellMetrics.dockHostMetrics.tabStripMetrics.layoutMetrics.headerHeight = detachedTitleBarTabHeight; } const UIEditorWorkspaceLayoutSnapshot preUpdateSnapshot = workspaceController.CaptureLayoutSnapshot(); const Widgets::UIEditorDockHostLayout preUpdateDockLayout = m_shellFrame.workspaceInteractionFrame.dockHostFrame.layout; m_hierarchyPanel.SetSceneRuntime(&context.GetSceneRuntime()); m_hierarchyPanel.SetCommandFocusService(&context.GetCommandFocusService()); m_sceneEditCommandRoute.BindSceneRuntime(&context.GetSceneRuntime()); m_sceneViewportController.SetCommandFocusService(&context.GetCommandFocusService()); // Keep the previous render request available for readback-based picking during // this update, then refresh it again after camera/navigation state changes. m_viewportHostService.SetSceneViewportRenderRequest( context.GetSceneRuntime().BuildSceneViewportRenderRequest()); context.BindEditCommandRoutes( &m_hierarchyPanel, &m_projectPanel, &m_sceneEditCommandRoute, &m_inspectorPanel); context.SyncSessionFromWorkspace(workspaceController); UIEditorShellInteractionDefinition definition = context.BuildShellDefinition(workspaceController, captureText, shellVariant); m_viewportHostService.BeginFrame(); const std::vector<::XCEngine::UI::UIInputEvent> shellEvents = HasHostedContentCapture() ? FilterShellInputEventsForHostedContentCapture(inputEvents) : inputEvents; m_shellFrame = UpdateUIEditorShellInteraction( m_shellInteractionState, workspaceController, bounds, definition, shellEvents, context.GetShellServices(), metrics); if (TryApplyUIEditorWorkspaceSplitterDragCorrection( m_splitterDragCorrectionState, m_shellInteractionState.workspaceInteractionState.dockHostInteractionState, preUpdateSnapshot, preUpdateDockLayout, workspaceController, metrics.shellMetrics.dockHostMetrics)) { context.SyncSessionFromWorkspace(workspaceController); definition = context.BuildShellDefinition(workspaceController, captureText, shellVariant); m_shellFrame = UpdateUIEditorShellInteraction( m_shellInteractionState, workspaceController, bounds, definition, {}, context.GetShellServices(), metrics); } const bool shellOwnsHostedContentPointerStream = ShouldHostedContentYieldPointerStream(m_shellFrame, HasShellInteractiveCapture()); const std::vector<::XCEngine::UI::UIInputEvent> hostedContentEvents = FilterHostedContentInputEventsForShellOwnership( inputEvents, shellOwnsHostedContentPointerStream); m_sceneViewportController.Update( context.GetSceneRuntime(), m_viewportHostService, m_shellInteractionState.workspaceInteractionState.composeState, m_shellFrame.workspaceInteractionFrame.composeFrame); m_viewportHostService.SetSceneViewportRenderRequest( context.GetSceneRuntime().BuildSceneViewportRenderRequest()); ApplyViewportFramesToShellFrame(m_shellFrame, m_viewportHostService); context.SyncSessionFromWorkspace(workspaceController); context.UpdateStatusFromShellResult(workspaceController, m_shellFrame.result); const std::string& activePanelId = workspaceController.GetWorkspace().activePanelId; m_projectPanel.SetProjectRuntime(&context.GetProjectRuntime()); m_projectPanel.SetCommandFocusService(&context.GetCommandFocusService()); m_inspectorPanel.SetCommandFocusService(&context.GetCommandFocusService()); m_hierarchyPanel.Update( m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame, hostedContentEvents, !m_shellFrame.result.workspaceInputSuppressed, activePanelId == kHierarchyPanelId); m_projectPanel.Update( m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame, hostedContentEvents, !m_shellFrame.result.workspaceInputSuppressed, activePanelId == kProjectPanelId); m_traceEntries = SyncWorkspaceEvents(context, *this); m_inspectorPanel.Update( context.GetSession(), context.GetSceneRuntime(), m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame, hostedContentEvents, !m_shellFrame.result.workspaceInputSuppressed, activePanelId == kInspectorPanelId); context.SyncSessionFromCommandFocusService(); m_consolePanel.Update( context.GetSession(), m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame); } } // namespace XCEngine::UI::Editor::App