From a600e73fb23ac8c2a0b061c5a7fb5fd8f6179adc Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Sun, 5 Apr 2026 17:48:12 +0800 Subject: [PATCH] Restore split layout panel render wrapper --- new_editor/src/panels/XCUILayoutLabPanel.cpp | 240 +++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 new_editor/src/panels/XCUILayoutLabPanel.cpp diff --git a/new_editor/src/panels/XCUILayoutLabPanel.cpp b/new_editor/src/panels/XCUILayoutLabPanel.cpp new file mode 100644 index 00000000..46867202 --- /dev/null +++ b/new_editor/src/panels/XCUILayoutLabPanel.cpp @@ -0,0 +1,240 @@ +#include "XCUILayoutLabPanel.h" + +#include "XCUIBackend/NullXCUIPanelCanvasHost.h" + +#include + +#include + +#include +#include +#include + +namespace XCEngine { +namespace NewEditor { + +namespace { + +constexpr char kPreviewDebugName[] = "XCUI Layout Lab"; + +bool ContainsPoint(const UI::UIRect& rect, const UI::UIPoint& point) { + return point.x >= rect.x && + point.y >= rect.y && + point.x <= rect.x + rect.width && + point.y <= rect.y + rect.height; +} + +const char* GetPreviewPathLabel( + const ::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter* previewPresenter) { + if (previewPresenter == nullptr) { + return "not injected"; + } + + return previewPresenter->IsNativeQueued() + ? "native queued offscreen surface" + : "hosted presenter"; +} + +::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot BuildPassiveSnapshot( + const ::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasSession& canvasSession, + const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeCaptureOptions& options) { + ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot snapshot = {}; + snapshot.pointerPosition = canvasSession.pointerPosition; + snapshot.pointerInside = options.hasPointerInsideOverride + ? options.pointerInsideOverride + : (canvasSession.validCanvas && canvasSession.hovered); + snapshot.windowFocused = options.windowFocused; + snapshot.timestampNanoseconds = options.timestampNanoseconds; + return snapshot; +} + +::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot CapturePanelSnapshot( + ::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* inputSource, + const ::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasSession& canvasSession) { + ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeCaptureOptions bridgeOptions = {}; + bridgeOptions.timestampNanoseconds = static_cast( + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count()); + + if (inputSource != nullptr) { + bridgeOptions.hasPointerInsideOverride = true; + bridgeOptions.windowFocused = canvasSession.windowFocused; + const UI::UIPoint pointerPosition = inputSource->GetPointerPosition(); + bridgeOptions.pointerInsideOverride = + canvasSession.validCanvas && ContainsPoint(canvasSession.canvasRect, pointerPosition); + return inputSource->CaptureSnapshot(bridgeOptions); + } + + bridgeOptions.hasPointerInsideOverride = true; + bridgeOptions.pointerInsideOverride = canvasSession.validCanvas && canvasSession.hovered; + bridgeOptions.windowFocused = canvasSession.windowFocused; + return BuildPassiveSnapshot(canvasSession, bridgeOptions); +} + +} // namespace + +void XCUILayoutLabPanel::Render() { + ImGui::SetNextWindowSize(ImVec2(960.0f, 720.0f), ImGuiCond_Appearing); + ImGui::SetNextWindowDockID(ImGui::GetID("XCNewEditorDockSpace"), ImGuiCond_Appearing); + + bool open = true; + if (!ImGui::Begin(GetName().c_str(), &open)) { + ImGui::End(); + if (!open) { + SetVisible(false); + } + return; + } + + if (ImGui::Button("Reload Layout Lab")) { + m_lastReloadSucceeded = m_runtime.ReloadDocuments(); + } + ImGui::SameLine(); + ImGui::TextUnformatted(m_lastReloadSucceeded ? "Reload: OK" : "Reload: Failed"); + ImGui::Separator(); + + const float diagnosticsHeight = 240.0f; + const ImVec2 hostRegion = ImGui::GetContentRegionAvail(); + const float canvasHeight = (std::max)(140.0f, hostRegion.y - diagnosticsHeight); + + if (m_canvasHost == nullptr) { + m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateNullXCUIPanelCanvasHost(); + } + + const bool nativeHostedPreview = IsUsingNativeHostedPreview(); + ::XCEngine::Editor::XCUIBackend::XCUIHostedPreviewSurfaceImage hostedSurfaceImage = {}; + const bool showHostedSurfaceImage = + nativeHostedPreview && + m_previewPresenter != nullptr && + m_previewPresenter->TryGetSurfaceImage(kPreviewDebugName, hostedSurfaceImage); + const char* const previewPathLabel = GetPreviewPathLabel(m_previewPresenter.get()); + ::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasRequest canvasRequest = {}; + canvasRequest.childId = "XCUILayoutLabCanvasHost"; + canvasRequest.height = canvasHeight; + canvasRequest.showSurfaceImage = showHostedSurfaceImage; + canvasRequest.surfaceImage = hostedSurfaceImage; + canvasRequest.placeholderTitle = + nativeHostedPreview ? "Native layout preview pending" : "Injected layout canvas host"; + canvasRequest.placeholderSubtitle = + nativeHostedPreview + ? "Waiting for native queued render output to publish back into the layout sandbox." + : "Inject a concrete canvas host to render the layout sandbox inside this panel."; + canvasRequest.badgeTitle = "Layout Lab"; + canvasRequest.badgeSubtitle = previewPathLabel; + const ::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasSession canvasSession = + m_canvasHost->BeginCanvas(canvasRequest); + const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot snapshot = + CapturePanelSnapshot(m_inputSource, canvasSession); + const XCUILayoutLabFrameCompositionRequest compositionRequest = { + canvasSession, + snapshot + }; + const XCUILayoutLabFrameComposition& composition = ComposeFrame(compositionRequest); + m_canvasHost->EndCanvas(); + + ImGui::Separator(); + ImGui::BeginChild("XCUILayoutLabDiagnostics", ImVec2(0.0f, 0.0f), false, ImGuiWindowFlags_NoScrollbar); + ImGui::SeparatorText("Preview"); + ImGui::Text( + "Path: %s | state: %s", + composition.previewPathLabel.c_str(), + composition.previewStateLabel.c_str()); + ImGui::Text( + "Presenter: presented %s | submit->native %s", + composition.previewStats.presented ? "yes" : "no", + composition.previewStats.queuedToNativePass ? "yes" : "no"); + ImGui::Text( + "Submitted: %zu lists / %zu cmds | Flushed: %zu lists / %zu cmds", + composition.previewStats.submittedDrawListCount, + composition.previewStats.submittedCommandCount, + composition.previewStats.flushedDrawListCount, + composition.previewStats.flushedCommandCount); + ImGui::TextWrapped("Source: %s", composition.previewSourceLabel.c_str()); + if (nativeHostedPreview) { + ImGui::Text( + "Surface descriptor: %s | image published: %s | queued frame index: %zu", + composition.hasHostedSurfaceDescriptor ? "yes" : "no", + composition.showHostedSurfaceImage ? "yes" : "no", + composition.hasHostedSurfaceDescriptor ? composition.hostedSurfaceDescriptor.queuedFrameIndex : 0u); + if (composition.hasHostedSurfaceDescriptor) { + ImGui::Text( + "Surface: %ux%u | logical: %.0f x %.0f | rendered rect: %.0f, %.0f %.0f x %.0f", + composition.hostedSurfaceDescriptor.image.surfaceWidth, + composition.hostedSurfaceDescriptor.image.surfaceHeight, + composition.hostedSurfaceDescriptor.logicalSize.width, + composition.hostedSurfaceDescriptor.logicalSize.height, + composition.hostedSurfaceDescriptor.image.renderedCanvasRect.x, + composition.hostedSurfaceDescriptor.image.renderedCanvasRect.y, + composition.hostedSurfaceDescriptor.image.renderedCanvasRect.width, + composition.hostedSurfaceDescriptor.image.renderedCanvasRect.height); + } else { + ImGui::TextDisabled("No native surface descriptor has been published back yet."); + } + } else { + ImGui::TextDisabled("No native surface descriptor is available without a native queued presenter."); + } + + ImGui::SeparatorText("Runtime"); + const ::XCEngine::Editor::XCUIBackend::XCUILayoutLabFrameStats& stats = + composition.frameResult != nullptr + ? composition.frameResult->stats + : m_runtime.GetFrameResult().stats; + ImGui::Text("Status: %s", stats.statusMessage.c_str()); + ImGui::Text( + "Rows: %zu | Columns: %zu | Overlays: %zu | Scroll views: %zu", + stats.rowCount, + stats.columnCount, + stats.overlayCount, + stats.scrollViewCount); + ImGui::Text( + "Tree items: %zu (%zu expanded) | Property sections: %zu (%zu expanded)", + stats.treeItemCount, + stats.expandedTreeItemCount, + stats.propertySectionCount, + stats.expandedPropertySectionCount); + ImGui::Text( + "Draw lists: %zu | Draw commands: %zu", + stats.drawListCount, + stats.commandCount); + ImGui::Text( + "Command types: fill %zu | outline %zu | text %zu | image %zu | clip %zu/%zu", + stats.filledRectCommandCount, + stats.rectOutlineCommandCount, + stats.textCommandCount, + stats.imageCommandCount, + stats.clipPushCommandCount, + stats.clipPopCommandCount); + ImGui::Text( + "Native overlay: %s | supported %zu | unsupported %zu", + stats.nativeOverlayReady ? "preflight OK" : "preflight issues", + stats.nativeSupportedCommandCount, + stats.nativeUnsupportedCommandCount); + ImGui::TextWrapped( + "Native note: %s", + stats.nativeOverlayStatusMessage.empty() ? "none" : stats.nativeOverlayStatusMessage.c_str()); + ImGui::Text( + "Hovered: %s | Selected: %s | canvas: %.0f x %.0f", + stats.hoveredElementId.empty() ? "none" : stats.hoveredElementId.c_str(), + stats.selectedElementId.empty() ? "none" : stats.selectedElementId.c_str(), + composition.inputState.canvasRect.width, + composition.inputState.canvasRect.height); + + ImGui::SeparatorText("Input"); + ImGui::Text( + "Pointer: %.0f, %.0f | inside %s | pressed %s", + composition.inputState.pointerPosition.x, + composition.inputState.pointerPosition.y, + composition.inputState.pointerInside ? "yes" : "no", + composition.inputState.pointerPressed ? "yes" : "no"); + ImGui::EndChild(); + + ImGui::End(); + + if (!open) { + SetVisible(false); + } +} + +} // namespace NewEditor +} // namespace XCEngine