Restore split layout panel render wrapper
This commit is contained in:
240
new_editor/src/panels/XCUILayoutLabPanel.cpp
Normal file
240
new_editor/src/panels/XCUILayoutLabPanel.cpp
Normal file
@@ -0,0 +1,240 @@
|
||||
#include "XCUILayoutLabPanel.h"
|
||||
|
||||
#include "XCUIBackend/NullXCUIPanelCanvasHost.h"
|
||||
|
||||
#include <XCEngine/UI/Types.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
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::uint64_t>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
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
|
||||
Reference in New Issue
Block a user