2026-04-05 04:55:25 +08:00
|
|
|
#include "XCUIDemoPanel.h"
|
|
|
|
|
|
2026-04-05 06:34:15 +08:00
|
|
|
#include "XCUIBackend/ImGuiXCUIHostedPreviewPresenter.h"
|
2026-04-05 04:55:25 +08:00
|
|
|
#include "XCUIBackend/ImGuiXCUIInputAdapter.h"
|
|
|
|
|
|
|
|
|
|
#include <XCEngine/UI/Types.h>
|
|
|
|
|
|
|
|
|
|
#include <imgui.h>
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
|
|
namespace XCEngine {
|
|
|
|
|
namespace NewEditor {
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
constexpr float kCanvasHudHeight = 82.0f;
|
|
|
|
|
constexpr float kCanvasHudPadding = 10.0f;
|
|
|
|
|
constexpr ImU32 kPreviewFrameColor = IM_COL32(54, 72, 94, 255);
|
|
|
|
|
constexpr ImU32 kPreviewPlaceholderFill = IM_COL32(18, 24, 32, 255);
|
|
|
|
|
constexpr ImU32 kPreviewPlaceholderText = IM_COL32(191, 205, 224, 255);
|
|
|
|
|
constexpr ImU32 kPreviewPlaceholderSubtleText = IM_COL32(132, 147, 170, 255);
|
|
|
|
|
constexpr char kPreviewDebugName[] = "XCUI Demo";
|
|
|
|
|
constexpr char kPreviewDebugSource[] = "new_editor.panels.xcui_demo";
|
|
|
|
|
|
|
|
|
|
UI::UIRect ToUIRect(const ImVec2& minPoint, const ImVec2& size) {
|
|
|
|
|
return UI::UIRect(minPoint.x, minPoint.y, size.x, size.y);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-05 06:34:15 +08:00
|
|
|
ImTextureID ToImTextureId(const UI::UITextureHandle& texture) {
|
|
|
|
|
return texture.IsValid()
|
|
|
|
|
? static_cast<ImTextureID>(texture.nativeHandle)
|
|
|
|
|
: ImTextureID{};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImVec2 ToImVec2(const UI::UIPoint& point) {
|
|
|
|
|
return ImVec2(point.x, point.y);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-05 04:55:25 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawHostedPreviewFrame(
|
|
|
|
|
ImDrawList* drawList,
|
|
|
|
|
const ImVec2& minPoint,
|
|
|
|
|
const ImVec2& size) {
|
|
|
|
|
if (drawList == nullptr || size.x <= 1.0f || size.y <= 1.0f) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ImVec2 maxPoint(minPoint.x + size.x, minPoint.y + size.y);
|
|
|
|
|
drawList->AddRect(minPoint, maxPoint, kPreviewFrameColor, 8.0f, 0, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawHostedPreviewPlaceholder(
|
|
|
|
|
ImDrawList* drawList,
|
|
|
|
|
const ImVec2& minPoint,
|
|
|
|
|
const ImVec2& size,
|
|
|
|
|
const char* title,
|
|
|
|
|
const char* subtitle) {
|
|
|
|
|
if (drawList == nullptr || size.x <= 1.0f || size.y <= 1.0f) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ImVec2 maxPoint(minPoint.x + size.x, minPoint.y + size.y);
|
|
|
|
|
drawList->AddRectFilled(minPoint, maxPoint, kPreviewPlaceholderFill, 8.0f);
|
|
|
|
|
drawList->AddRect(minPoint, maxPoint, kPreviewFrameColor, 8.0f, 0, 1.0f);
|
|
|
|
|
drawList->AddText(ImVec2(minPoint.x + 14.0f, minPoint.y + 14.0f), kPreviewPlaceholderText, title);
|
|
|
|
|
if (subtitle != nullptr && subtitle[0] != '\0') {
|
|
|
|
|
drawList->AddText(
|
|
|
|
|
ImVec2(minPoint.x + 14.0f, minPoint.y + 36.0f),
|
|
|
|
|
kPreviewPlaceholderSubtleText,
|
|
|
|
|
subtitle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawRectOverlay(
|
|
|
|
|
ImDrawList* drawList,
|
|
|
|
|
::XCEngine::Editor::XCUIBackend::XCUIDemoRuntime& runtime,
|
|
|
|
|
const std::string& elementId,
|
|
|
|
|
ImU32 color,
|
|
|
|
|
const char* label) {
|
|
|
|
|
if (drawList == nullptr || elementId.empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UI::UIRect rect = {};
|
|
|
|
|
if (!runtime.TryGetElementRect(elementId, rect)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ImVec2 minPoint(rect.x, rect.y);
|
|
|
|
|
const ImVec2 maxPoint(rect.x + rect.width, rect.y + rect.height);
|
|
|
|
|
drawList->AddRect(minPoint, maxPoint, color, 6.0f, 0, 2.0f);
|
|
|
|
|
if (label != nullptr && label[0] != '\0') {
|
|
|
|
|
drawList->AddText(ImVec2(minPoint.x + 4.0f, minPoint.y + 4.0f), color, label);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* GetPreviewPathLabel(bool nativeHostedPreview) {
|
|
|
|
|
return nativeHostedPreview ? "native queued offscreen surface" : "legacy imgui transition";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* GetPreviewStateLabel(
|
|
|
|
|
bool nativeHostedPreview,
|
|
|
|
|
const ::XCEngine::Editor::XCUIBackend::XCUIHostedPreviewStats& previewStats,
|
|
|
|
|
bool hasHostedSurfaceDescriptor,
|
|
|
|
|
bool showHostedSurfaceImage) {
|
|
|
|
|
if (nativeHostedPreview) {
|
|
|
|
|
if (showHostedSurfaceImage) {
|
|
|
|
|
return "live";
|
|
|
|
|
}
|
|
|
|
|
if (previewStats.queuedToNativePass || hasHostedSurfaceDescriptor) {
|
|
|
|
|
return "warming";
|
|
|
|
|
}
|
|
|
|
|
return "awaiting submit";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return previewStats.presented ? "live" : "idle";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
XCUIDemoPanel::XCUIDemoPanel(::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* inputSource)
|
|
|
|
|
: XCUIDemoPanel(inputSource, ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIHostedPreviewPresenter()) {}
|
|
|
|
|
|
|
|
|
|
XCUIDemoPanel::XCUIDemoPanel(
|
|
|
|
|
::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* inputSource,
|
|
|
|
|
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> previewPresenter)
|
|
|
|
|
: Panel("XCUI Demo")
|
|
|
|
|
, m_inputSource(inputSource)
|
|
|
|
|
, m_previewPresenter(std::move(previewPresenter)) {
|
|
|
|
|
if (m_previewPresenter == nullptr) {
|
|
|
|
|
m_previewPresenter = ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIHostedPreviewPresenter();
|
|
|
|
|
}
|
|
|
|
|
m_lastReloadSucceeded = m_runtime.ReloadDocuments();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void XCUIDemoPanel::SetHostedPreviewEnabled(bool enabled) {
|
|
|
|
|
m_hostedPreviewEnabled = enabled;
|
|
|
|
|
if (!m_hostedPreviewEnabled) {
|
|
|
|
|
m_lastPreviewStats = {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ::XCEngine::Editor::XCUIBackend::XCUIDemoFrameResult& XCUIDemoPanel::GetFrameResult() const {
|
|
|
|
|
return m_runtime.GetFrameResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ::XCEngine::Editor::XCUIBackend::XCUIHostedPreviewStats& XCUIDemoPanel::GetLastPreviewStats() const {
|
|
|
|
|
return m_lastPreviewStats;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void XCUIDemoPanel::SetHostedPreviewPresenter(
|
|
|
|
|
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> previewPresenter) {
|
|
|
|
|
m_previewPresenter = std::move(previewPresenter);
|
|
|
|
|
if (m_previewPresenter == nullptr) {
|
|
|
|
|
m_previewPresenter = ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIHostedPreviewPresenter();
|
|
|
|
|
}
|
|
|
|
|
m_lastPreviewStats = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool XCUIDemoPanel::IsUsingNativeHostedPreview() const {
|
|
|
|
|
return m_previewPresenter != nullptr && m_previewPresenter->IsNativeQueued();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void XCUIDemoPanel::Render() {
|
|
|
|
|
ImGui::SetNextWindowSize(ImVec2(1040.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 Documents")) {
|
|
|
|
|
m_lastReloadSucceeded = m_runtime.ReloadDocuments();
|
|
|
|
|
}
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
ImGui::Checkbox("Canvas HUD", &m_showCanvasHud);
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
ImGui::Checkbox("Debug Rects", &m_showDebugRects);
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
ImGui::TextUnformatted(m_lastReloadSucceeded ? "Reload: OK" : "Reload: Failed");
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
|
|
|
|
|
const float diagnosticsHeight = 232.0f;
|
|
|
|
|
const ImVec2 hostRegion = ImGui::GetContentRegionAvail();
|
|
|
|
|
const float canvasHeight = (std::max)(140.0f, hostRegion.y - diagnosticsHeight);
|
|
|
|
|
|
|
|
|
|
ImGui::BeginChild("XCUIDemoCanvasHost", ImVec2(0.0f, canvasHeight), true, ImGuiWindowFlags_NoScrollWithMouse);
|
|
|
|
|
const ImVec2 canvasHostMin = ImGui::GetCursorScreenPos();
|
|
|
|
|
const ImVec2 availableSize = ImGui::GetContentRegionAvail();
|
|
|
|
|
const float topInset = m_showCanvasHud ? (kCanvasHudHeight + kCanvasHudPadding) : 0.0f;
|
|
|
|
|
const ImVec2 canvasMin(canvasHostMin.x, canvasHostMin.y + topInset);
|
|
|
|
|
const ImVec2 canvasSize(
|
|
|
|
|
availableSize.x,
|
|
|
|
|
(std::max)(0.0f, availableSize.y - topInset));
|
|
|
|
|
const bool validCanvas = canvasSize.x > 1.0f && canvasSize.y > 1.0f;
|
|
|
|
|
const bool nativeHostedPreview = IsUsingNativeHostedPreview();
|
|
|
|
|
::XCEngine::Editor::XCUIBackend::XCUIHostedPreviewSurfaceDescriptor hostedSurfaceDescriptor = {};
|
|
|
|
|
const bool hasHostedSurfaceDescriptor =
|
|
|
|
|
nativeHostedPreview &&
|
|
|
|
|
m_previewPresenter != nullptr &&
|
|
|
|
|
m_previewPresenter->TryGetSurfaceDescriptor(kPreviewDebugName, hostedSurfaceDescriptor);
|
|
|
|
|
::XCEngine::Editor::XCUIBackend::XCUIHostedPreviewSurfaceImage hostedSurfaceImage = {};
|
|
|
|
|
const bool showHostedSurfaceImage =
|
|
|
|
|
validCanvas &&
|
|
|
|
|
nativeHostedPreview &&
|
|
|
|
|
m_previewPresenter != nullptr &&
|
|
|
|
|
m_previewPresenter->TryGetSurfaceImage(kPreviewDebugName, hostedSurfaceImage);
|
|
|
|
|
const char* const previewPathLabel = GetPreviewPathLabel(nativeHostedPreview);
|
|
|
|
|
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
|
|
|
|
|
|
|
|
|
if (validCanvas) {
|
|
|
|
|
ImGui::SetCursorScreenPos(canvasMin);
|
|
|
|
|
if (showHostedSurfaceImage) {
|
2026-04-05 06:34:15 +08:00
|
|
|
ImGui::Image(
|
|
|
|
|
ToImTextureId(hostedSurfaceImage.texture),
|
|
|
|
|
canvasSize,
|
|
|
|
|
ToImVec2(hostedSurfaceImage.uvMin),
|
|
|
|
|
ToImVec2(hostedSurfaceImage.uvMax));
|
2026-04-05 04:55:25 +08:00
|
|
|
DrawHostedPreviewFrame(drawList, canvasMin, canvasSize);
|
|
|
|
|
} else {
|
|
|
|
|
ImGui::InvisibleButton("##XCUIDemoCanvas", canvasSize);
|
|
|
|
|
const char* placeholderSubtitle =
|
|
|
|
|
nativeHostedPreview
|
|
|
|
|
? "Waiting for native queued render output to publish back into the sandbox panel."
|
|
|
|
|
: "Legacy ImGui transition path stays active until native offscreen preview is enabled.";
|
|
|
|
|
DrawHostedPreviewPlaceholder(
|
|
|
|
|
drawList,
|
|
|
|
|
canvasMin,
|
|
|
|
|
canvasSize,
|
|
|
|
|
nativeHostedPreview ? "Native XCUI preview pending" : "Legacy XCUI canvas host",
|
|
|
|
|
placeholderSubtitle);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ImGui::Dummy(ImVec2(0.0f, 0.0f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::XCEngine::Editor::XCUIBackend::XCUIDemoInputState input = {};
|
|
|
|
|
::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());
|
|
|
|
|
const UI::UIRect canvasRect = ToUIRect(canvasMin, canvasSize);
|
|
|
|
|
|
|
|
|
|
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot snapshot = {};
|
|
|
|
|
if (m_inputSource != nullptr) {
|
|
|
|
|
bridgeOptions.hasPointerInsideOverride = true;
|
|
|
|
|
bridgeOptions.windowFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
|
|
|
|
|
const UI::UIPoint pointerPosition = m_inputSource->GetPointerPosition();
|
|
|
|
|
bridgeOptions.pointerInsideOverride = validCanvas && ContainsPoint(canvasRect, pointerPosition);
|
|
|
|
|
snapshot = m_inputSource->CaptureSnapshot(bridgeOptions);
|
|
|
|
|
} else {
|
|
|
|
|
bridgeOptions.hasPointerInsideOverride = true;
|
|
|
|
|
bridgeOptions.pointerInsideOverride = validCanvas && ImGui::IsItemHovered();
|
|
|
|
|
bridgeOptions.windowFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
|
|
|
|
|
snapshot = ::XCEngine::Editor::XCUIBackend::ImGuiXCUIInputAdapter::CaptureSnapshot(
|
|
|
|
|
ImGui::GetIO(),
|
|
|
|
|
bridgeOptions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_inputBridge.HasBaseline()) {
|
|
|
|
|
m_inputBridge.Prime(snapshot);
|
|
|
|
|
}
|
|
|
|
|
const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta frameDelta =
|
|
|
|
|
m_inputBridge.Translate(snapshot);
|
|
|
|
|
|
|
|
|
|
input.canvasRect = canvasRect;
|
|
|
|
|
input.pointerPosition = snapshot.pointerPosition;
|
|
|
|
|
input.pointerInside = snapshot.pointerInside;
|
|
|
|
|
input.pointerPressed = frameDelta.pointer.pressed[0];
|
|
|
|
|
input.pointerReleased = frameDelta.pointer.released[0];
|
|
|
|
|
input.pointerDown = snapshot.pointerButtonsDown[0];
|
|
|
|
|
input.windowFocused = snapshot.windowFocused;
|
|
|
|
|
input.shortcutPressed = false;
|
|
|
|
|
input.wantCaptureMouse = snapshot.wantCaptureMouse;
|
|
|
|
|
input.wantCaptureKeyboard = snapshot.wantCaptureKeyboard;
|
|
|
|
|
input.wantTextInput = snapshot.wantTextInput;
|
|
|
|
|
input.events = frameDelta.events;
|
|
|
|
|
|
|
|
|
|
const ::XCEngine::Editor::XCUIBackend::XCUIDemoFrameResult& frame = m_runtime.Update(input);
|
|
|
|
|
|
|
|
|
|
if (m_hostedPreviewEnabled && m_previewPresenter != nullptr) {
|
|
|
|
|
::XCEngine::Editor::XCUIBackend::XCUIHostedPreviewFrame previewFrame = {};
|
|
|
|
|
previewFrame.drawData = &frame.drawData;
|
|
|
|
|
previewFrame.canvasRect = canvasRect;
|
|
|
|
|
previewFrame.logicalSize = UI::UISize(canvasRect.width, canvasRect.height);
|
|
|
|
|
previewFrame.debugName = kPreviewDebugName;
|
|
|
|
|
previewFrame.debugSource = kPreviewDebugSource;
|
|
|
|
|
m_previewPresenter->Present(previewFrame);
|
|
|
|
|
m_lastPreviewStats = m_previewPresenter->GetLastStats();
|
|
|
|
|
} else {
|
|
|
|
|
m_lastPreviewStats = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ::XCEngine::Editor::XCUIBackend::XCUIDemoFrameStats& stats = frame.stats;
|
|
|
|
|
const char* const previewStateLabel = GetPreviewStateLabel(
|
|
|
|
|
nativeHostedPreview,
|
|
|
|
|
m_lastPreviewStats,
|
|
|
|
|
hasHostedSurfaceDescriptor,
|
|
|
|
|
showHostedSurfaceImage);
|
|
|
|
|
if (m_showCanvasHud) {
|
|
|
|
|
const ImVec2 hudMin(canvasHostMin.x + 8.0f, canvasHostMin.y + 8.0f);
|
|
|
|
|
const ImVec2 hudMax(
|
|
|
|
|
canvasHostMin.x + (std::min)(availableSize.x - 8.0f, 430.0f),
|
|
|
|
|
canvasHostMin.y + kCanvasHudHeight);
|
|
|
|
|
drawList->AddRectFilled(
|
|
|
|
|
hudMin,
|
|
|
|
|
hudMax,
|
|
|
|
|
IM_COL32(16, 22, 30, 220),
|
|
|
|
|
8.0f);
|
|
|
|
|
drawList->AddRect(
|
|
|
|
|
hudMin,
|
|
|
|
|
hudMax,
|
|
|
|
|
IM_COL32(52, 72, 96, 255),
|
|
|
|
|
8.0f,
|
|
|
|
|
0,
|
|
|
|
|
1.0f);
|
|
|
|
|
|
|
|
|
|
ImGui::SetCursorScreenPos(ImVec2(hudMin.x + 10.0f, hudMin.y + 8.0f));
|
|
|
|
|
ImGui::BeginGroup();
|
|
|
|
|
ImGui::TextUnformatted("XCUI Runtime");
|
|
|
|
|
ImGui::Text("%s | %s", previewPathLabel, previewStateLabel);
|
|
|
|
|
ImGui::TextUnformatted(stats.statusMessage.c_str());
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Tree %llu | Elements %zu | Commands %zu",
|
|
|
|
|
static_cast<unsigned long long>(stats.treeGeneration),
|
|
|
|
|
stats.elementCount,
|
|
|
|
|
stats.commandCount);
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Submit %zu/%zu | Flush %zu/%zu",
|
|
|
|
|
m_lastPreviewStats.submittedDrawListCount,
|
|
|
|
|
m_lastPreviewStats.submittedCommandCount,
|
|
|
|
|
m_lastPreviewStats.flushedDrawListCount,
|
|
|
|
|
m_lastPreviewStats.flushedCommandCount);
|
|
|
|
|
ImGui::EndGroup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_showDebugRects && validCanvas && (!nativeHostedPreview || showHostedSurfaceImage)) {
|
|
|
|
|
DrawRectOverlay(drawList, m_runtime, stats.hoveredElementId, IM_COL32(255, 195, 64, 255), "hover");
|
|
|
|
|
DrawRectOverlay(drawList, m_runtime, stats.focusedElementId, IM_COL32(64, 214, 255, 255), "focus");
|
|
|
|
|
DrawRectOverlay(drawList, m_runtime, "toggleAccent", IM_COL32(150, 255, 150, 160), "toggle");
|
|
|
|
|
}
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
ImGui::BeginChild("XCUIDemoDiagnostics", ImVec2(0.0f, 0.0f), false, ImGuiWindowFlags_NoScrollbar);
|
|
|
|
|
ImGui::SeparatorText("Preview");
|
|
|
|
|
ImGui::Text("Path: %s | state: %s", previewPathLabel, previewStateLabel);
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Presenter: presented %s | submit->native %s",
|
|
|
|
|
m_lastPreviewStats.presented ? "yes" : "no",
|
|
|
|
|
m_lastPreviewStats.queuedToNativePass ? "yes" : "no");
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Submitted: %zu lists / %zu cmds | Flushed: %zu lists / %zu cmds",
|
|
|
|
|
m_lastPreviewStats.submittedDrawListCount,
|
|
|
|
|
m_lastPreviewStats.submittedCommandCount,
|
|
|
|
|
m_lastPreviewStats.flushedDrawListCount,
|
|
|
|
|
m_lastPreviewStats.flushedCommandCount);
|
|
|
|
|
ImGui::TextWrapped(
|
|
|
|
|
"Source: %s",
|
|
|
|
|
hasHostedSurfaceDescriptor && !hostedSurfaceDescriptor.debugSource.empty()
|
|
|
|
|
? hostedSurfaceDescriptor.debugSource.c_str()
|
|
|
|
|
: kPreviewDebugSource);
|
|
|
|
|
if (nativeHostedPreview) {
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Surface descriptor: %s | image published: %s | queued frame index: %zu",
|
|
|
|
|
hasHostedSurfaceDescriptor ? "yes" : "no",
|
|
|
|
|
showHostedSurfaceImage ? "yes" : "no",
|
|
|
|
|
hasHostedSurfaceDescriptor ? hostedSurfaceDescriptor.queuedFrameIndex : 0u);
|
|
|
|
|
if (hasHostedSurfaceDescriptor) {
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Surface: %ux%u | logical: %.0f x %.0f | rendered rect: %.0f, %.0f %.0f x %.0f",
|
|
|
|
|
hostedSurfaceDescriptor.image.surfaceWidth,
|
|
|
|
|
hostedSurfaceDescriptor.image.surfaceHeight,
|
|
|
|
|
hostedSurfaceDescriptor.logicalSize.width,
|
|
|
|
|
hostedSurfaceDescriptor.logicalSize.height,
|
|
|
|
|
hostedSurfaceDescriptor.image.renderedCanvasRect.x,
|
|
|
|
|
hostedSurfaceDescriptor.image.renderedCanvasRect.y,
|
|
|
|
|
hostedSurfaceDescriptor.image.renderedCanvasRect.width,
|
|
|
|
|
hostedSurfaceDescriptor.image.renderedCanvasRect.height);
|
|
|
|
|
} else {
|
|
|
|
|
ImGui::TextDisabled("No native surface descriptor has been published back yet.");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ImGui::TextDisabled("Legacy path renders directly into the panel draw list. No native surface descriptor exists.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::SeparatorText("Runtime");
|
|
|
|
|
ImGui::Text("Status: %s", stats.statusMessage.c_str());
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Tree gen: %llu | elements: %zu | dirty roots: %zu",
|
|
|
|
|
static_cast<unsigned long long>(stats.treeGeneration),
|
|
|
|
|
stats.elementCount,
|
|
|
|
|
stats.dirtyRootCount);
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Draw lists: %zu | draw cmds: %zu | dependencies: %zu",
|
|
|
|
|
stats.drawListCount,
|
|
|
|
|
stats.commandCount,
|
|
|
|
|
stats.dependencyCount);
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Hovered: %s | Focused: %s",
|
|
|
|
|
stats.hoveredElementId.empty() ? "none" : stats.hoveredElementId.c_str(),
|
|
|
|
|
stats.focusedElementId.empty() ? "none" : stats.focusedElementId.c_str());
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Last command: %s | Accent: %s",
|
|
|
|
|
stats.lastCommandId.empty() ? "none" : stats.lastCommandId.c_str(),
|
|
|
|
|
stats.accentEnabled ? "on" : "off");
|
|
|
|
|
ImGui::Text("Canvas: %.0f x %.0f", input.canvasRect.width, input.canvasRect.height);
|
|
|
|
|
|
|
|
|
|
ImGui::SeparatorText("Input");
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Pointer: %.0f, %.0f | inside %s | down %s | pressed %s | released %s",
|
|
|
|
|
input.pointerPosition.x,
|
|
|
|
|
input.pointerPosition.y,
|
|
|
|
|
input.pointerInside ? "yes" : "no",
|
|
|
|
|
input.pointerDown ? "yes" : "no",
|
|
|
|
|
input.pointerPressed ? "yes" : "no",
|
|
|
|
|
input.pointerReleased ? "yes" : "no");
|
|
|
|
|
ImGui::Text(
|
|
|
|
|
"Focus %s | capture mouse %s | capture keyboard %s | text input %s | events %zu",
|
|
|
|
|
input.windowFocused ? "yes" : "no",
|
|
|
|
|
input.wantCaptureMouse ? "yes" : "no",
|
|
|
|
|
input.wantCaptureKeyboard ? "yes" : "no",
|
|
|
|
|
input.wantTextInput ? "yes" : "no",
|
|
|
|
|
input.events.size());
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
|
|
|
|
|
|
ImGui::End();
|
|
|
|
|
|
|
|
|
|
if (!open) {
|
|
|
|
|
SetVisible(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace NewEditor
|
|
|
|
|
} // namespace XCEngine
|