Contain XCUI ImGui adapters behind explicit host seams
This commit is contained in:
@@ -64,7 +64,7 @@ Current gap:
|
||||
### 3. Editor Layer
|
||||
|
||||
- `new_editor` remains the isolated XCUI sandbox.
|
||||
- Native hosted preview is working as `RHI offscreen surface -> ImGui shell texture embed`.
|
||||
- Native hosted preview is working as `RHI offscreen surface -> hosted surface image present` through the current shell adapter path.
|
||||
- Hosted preview surface descriptors now stay on XCUI-owned value types (`UITextureHandle`, `UIPoint`, `UIRect`) instead of exposing ImGui texture/UV types through the generic preview contract.
|
||||
- `XCUI Demo` remains the long-lived effect and behavior testbed.
|
||||
- `XCUI Demo` now covers both single-line and multiline text authoring behavior, including click caret placement, delete/backspace, tab indentation, and optional text-area line numbers.
|
||||
@@ -78,6 +78,8 @@ Current gap:
|
||||
- `XCUI Demo` now exports pending per-frame command ids through `DrainPendingCommandIds()`, so editor-side hosts have a clean seam for observing demo/runtime command traffic without parsing draw data.
|
||||
- `XCUI Demo` and `LayoutLab` panel canvases are now being pulled behind a dedicated `IXCUIPanelCanvasHost` seam, so canvas surface presentation, hover/focus fallback state, and overlay draw hooks no longer have to stay hard-coded inside each ImGui panel implementation.
|
||||
- The panel-canvas seam now also exposes explicit backend/capability metadata and a minimal `NullXCUIPanelCanvasHost`, so non-ImGui host paths have a concrete placeholder backend instead of relying on an implicit ImGui default.
|
||||
- `XCUI Demo` and `LayoutLab` panel input now also flows through an explicit `IXCUIInputSnapshotSource` seam, so panel/runtime code no longer reads `ImGuiIO` / `ImGui::IsKeyPressed` / `ImGui::IsMouseClicked` directly when the shell wants to use an ImGui adapter.
|
||||
- `new_editor` now also has an explicit `ImGuiXCUIInputSnapshotSource` adapter, keeping ImGui-specific input capture in the host adapter layer instead of inside panel/runtime update code.
|
||||
- Panel diagnostics were expanded to clearly separate preview/runtime/input state and native vs legacy paths.
|
||||
- The editor bridge layer now has smoke coverage for swapchain after-UI rendering hooks and SRV-backed ImGui texture descriptor registration.
|
||||
- `Application` no longer owns the ImGui backend directly; window presentation now routes through `IWindowUICompositor` with an `ImGuiWindowUICompositor` implementation, which currently delegates to `IEditorHostCompositor` / `ImGuiHostCompositor`.
|
||||
@@ -90,29 +92,33 @@ Current gap:
|
||||
- `LayoutLab` panel input now also maps concrete arrow/home/end keys into those shared navigation actions, so keyboard traversal is reachable from the sandbox UI instead of staying runtime-only.
|
||||
- `XCUIDemoRuntime` now bridges pointer activation, text-edit commands, and shortcut-triggered commands through a unified command path, and `DrainPendingCommandIds()` now preserves mixed pointer/text/shortcut ordering.
|
||||
- `new_editor` now also has a pure `XCUIShellChromeState` model covering panel visibility, hosted-preview mode, and shell-level view toggles without depending on ImGui, `Application`, or the old editor.
|
||||
- `XCUIShellChromeState` hosted-preview mode naming is now backend-neutral (`HostedPresenter` / `NativeOffscreen`) instead of encoding `ImGui` into the XCUI shell model.
|
||||
- `XCNewEditor` builds successfully to `build/new_editor/bin/Debug/XCNewEditor.exe`.
|
||||
|
||||
Current gap:
|
||||
|
||||
- The shell is still ImGui-hosted.
|
||||
- Legacy hosted preview still depends on an ImGui-specific inline draw target binding for presentation.
|
||||
- The new panel-canvas seam still only has an ImGui adapter today; a native panel/shell host still needs to replace it before ImGui can stop being the default editor host path.
|
||||
- Hosted-preview compatibility presentation still depends on an ImGui-specific inline draw target binding when the native queued surface path is disabled.
|
||||
- The panel-canvas seam still only has an ImGui adapter today; a native panel/shell host still needs to replace it before the editor shell can stop depending on ImGui host chrome.
|
||||
- Editor-specialized widgets are still incomplete at the shared-module level: the authored prototypes exist, but virtualization, multi-selection/focus traversal, toolbar/menu chrome, and icon-atlas widgets are not yet extracted into reusable XCUI modules, and broader editor-host keybinding plus full shell-state adoption are still only partially integrated.
|
||||
|
||||
## Validated This Phase
|
||||
|
||||
- `new_editor_xcui_demo_panel_tests`: `3/3`
|
||||
- `new_editor_xcui_demo_runtime_tests`: `12/12`
|
||||
- `new_editor_xcui_input_bridge_tests`: `4/4`
|
||||
- `new_editor_imgui_xcui_input_adapter_tests`: `2/2`
|
||||
- `new_editor_xcui_layout_lab_runtime_tests`: `12/12`
|
||||
- `new_editor_xcui_rhi_command_compiler_tests`: `6/6`
|
||||
- `new_editor_xcui_rhi_render_backend_tests`: `5/5`
|
||||
- `new_editor_xcui_hosted_preview_presenter_tests`: `17/17`
|
||||
- `new_editor_xcui_hosted_preview_presenter_tests`: `20/20`
|
||||
- `new_editor_imgui_window_ui_compositor_tests`: `7/7`
|
||||
- `new_editor_xcui_editor_command_router_tests`: `5/5`
|
||||
- `new_editor_application_shell_command_bindings_tests`: `6/6`
|
||||
- `new_editor_xcui_shell_chrome_state_tests`: `8/8`
|
||||
- `new_editor_xcui_panel_canvas_host_tests`: `2/2`
|
||||
- `new_editor_xcui_shell_chrome_state_tests`: `11/11`
|
||||
- `new_editor_xcui_panel_canvas_host_tests`: `4/4`
|
||||
- `new_editor_imgui_xcui_panel_canvas_host_tests`: `1/1`
|
||||
- `new_editor_xcui_layout_lab_panel_tests`: `2/2`
|
||||
- `new_editor_xcui_layout_lab_panel_tests`: `3/3`
|
||||
- `XCNewEditor` Debug target builds successfully
|
||||
- `core_ui_tests`: `52 total` (`50` passed, `2` skipped because `KeyCode::Delete` currently aliases `Backspace`)
|
||||
- `scene_tests`: `68/68`
|
||||
@@ -199,8 +205,12 @@ Current gap:
|
||||
- shell-level shortcuts now flow from `XCUIWin32InputSource` through `XCUIInputBridge` into command matching
|
||||
- hosted-preview mode toggles still trigger presenter reconfiguration through the routed command bindings
|
||||
- `new_editor` panel canvas ownership is now being split behind `IXCUIPanelCanvasHost`, with an `ImGuiXCUIPanelCanvasHost` adapter carrying the legacy path so panel code stops directly owning `ImGui::Image` / `ImGui::InvisibleButton` / draw-list preview plumbing.
|
||||
- `XCUIDemoPanel` and `XCUILayoutLabPanel` no longer create an ImGui hosted-preview presenter or ImGui panel canvas host implicitly; default construction now stays on null/explicitly injected backends until the outer shell binds a concrete host adapter.
|
||||
- `Application` now binds `ImGuiXCUIPanelCanvasHost` explicitly at the shell composition root, so the current ImGui panel host path is visible as a host-layer decision instead of a panel-layer fallback.
|
||||
- `XCUIDemoPanel` and `XCUILayoutLabPanel` no longer read ImGui input directly; both now consume an injected `IXCUIInputSnapshotSource`, and the new `ImGuiXCUIInputSnapshotSource` keeps the current ImGui-backed input path isolated behind an explicit adapter.
|
||||
- `new_editor` now also has a pure `XCUIShellChromeState` model with dedicated tests, covering shell panel visibility, hosted-preview mode, and shell view toggles without depending on ImGui or `Application`.
|
||||
- `XCUIShellChromeState` now also exposes effective hosted-preview state helpers and shell view-toggle command-id helpers, so shell routing code no longer has to manually combine enablement and requested preview mode.
|
||||
- `XCUIShellChromeState` hosted-preview modes were renamed away from `LegacyImGui`, so XCUI shell state no longer treats ImGui as the generic fallback concept.
|
||||
- The panel-canvas seam now has dedicated null/imgui backend coverage, including explicit backend/capability reporting and a non-ImGui placeholder host path for future native shell adoption.
|
||||
- `SceneRuntime` layered XCUI routing now has dedicated regression coverage for:
|
||||
- top-interactive layer input ownership
|
||||
@@ -228,13 +238,13 @@ Current gap:
|
||||
- `ScrollView` is still authored/static; no wheel-driven scrolling or virtualization yet.
|
||||
- `Image` widgets still do not have source-rect/atlas-subregion level API in the high-level draw command model.
|
||||
- Editor shell still depends on ImGui as host chrome.
|
||||
- Legacy hosted preview still depends on an ImGui-only inline presenter path when not using the queued native surface path.
|
||||
- Hosted-preview compatibility presentation still depends on an ImGui-only inline presenter path when not using the queued native surface path.
|
||||
- Editor widget coverage is still prototype-driven inside `LayoutLab`; it has not yet been promoted into a full reusable shared widget/runtime layer with command routing, virtualization, and property-edit transactions.
|
||||
|
||||
## Next Phase
|
||||
|
||||
1. Expand runtime/game-layer ownership from the current `SceneRuntime` UI context into scene-declared HUD/menu bootstrapping, draw submission, and higher-level runtime UI policies.
|
||||
2. Promote the current editor-facing widget prototypes out of authored `LayoutLab` content and into reusable XCUI widget/runtime modules, then continue with toolbar/menu chrome, shell-state adoption, and panel-level keyboard/navigation input plumbing.
|
||||
2. Promote the current editor-facing widget prototypes out of authored `LayoutLab` content and into reusable XCUI widget/runtime modules, then continue with toolbar/menu chrome, shell-state adoption, virtualization, and broader focus/multi-selection behavior.
|
||||
3. Add a native XCUI host compositor on the existing window-level compositor seam so `new_editor` can present without going through ImGui-owned draw data.
|
||||
4. Replace the remaining ImGui-only fallback seams in hosted preview and panel canvas hosting with native host implementations so ImGui can become compatibility-only instead of the default shell path.
|
||||
5. Continue phased validation, commit, push, and plan refresh after each stable batch.
|
||||
|
||||
@@ -53,7 +53,9 @@ set(NEW_EDITOR_SOURCES
|
||||
src/XCUIBackend/ImGuiHostCompositor.cpp
|
||||
src/XCUIBackend/XCUIEditorFontSetup.cpp
|
||||
src/XCUIBackend/XCUIAssetDocumentSource.cpp
|
||||
src/XCUIBackend/XCUIEditorCommandRouter.cpp
|
||||
src/XCUIBackend/XCUIInputBridge.cpp
|
||||
src/XCUIBackend/XCUIShellChromeState.cpp
|
||||
src/XCUIBackend/XCUIRHICommandCompiler.cpp
|
||||
src/XCUIBackend/XCUIRHIRenderBackend.cpp
|
||||
src/XCUIBackend/XCUIStandaloneTextAtlasProvider.cpp
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "Application.h"
|
||||
#include "XCUIBackend/ImGuiXCUIPanelCanvasHost.h"
|
||||
#include "XCUIBackend/ImGuiXCUIHostedPreviewPresenter.h"
|
||||
#include "XCUIBackend/ImGuiWindowUICompositor.h"
|
||||
|
||||
@@ -41,12 +42,12 @@ const char* GetHostedPreviewPathLabel(bool nativeRequested, bool nativePresenter
|
||||
return "native queued offscreen surface";
|
||||
}
|
||||
if (nativeRequested) {
|
||||
return "native requested, legacy presenter bound";
|
||||
return "native requested, hosted presenter bound";
|
||||
}
|
||||
if (nativePresenterBound) {
|
||||
return "legacy requested, native presenter still bound";
|
||||
return "hosted presenter requested, native presenter still bound";
|
||||
}
|
||||
return "legacy imgui transition";
|
||||
return "hosted presenter";
|
||||
}
|
||||
|
||||
const char* GetHostedPreviewStateLabel(
|
||||
@@ -90,70 +91,20 @@ Application::CreateHostedPreviewPresenter(bool nativePreview) {
|
||||
return ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIHostedPreviewPresenter();
|
||||
}
|
||||
|
||||
Application::ShellPanelChromeState* Application::TryGetShellPanelState(ShellPanelId panelId) {
|
||||
const std::size_t index = GetShellPanelIndex(panelId);
|
||||
if (index >= m_shellPanels.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &m_shellPanels[index];
|
||||
}
|
||||
|
||||
const Application::ShellPanelChromeState* Application::TryGetShellPanelState(ShellPanelId panelId) const {
|
||||
const std::size_t index = GetShellPanelIndex(panelId);
|
||||
if (index >= m_shellPanels.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &m_shellPanels[index];
|
||||
return m_shellChromeState.TryGetPanelState(panelId);
|
||||
}
|
||||
|
||||
bool Application::IsShellViewToggleEnabled(ShellViewToggleId toggleId) const {
|
||||
switch (toggleId) {
|
||||
case ShellViewToggleId::ImGuiDemoWindow:
|
||||
return m_shellViewToggles.imguiDemoWindowVisible;
|
||||
case ShellViewToggleId::NativeBackdrop:
|
||||
return m_shellViewToggles.nativeBackdropVisible;
|
||||
case ShellViewToggleId::PulseAccent:
|
||||
return m_shellViewToggles.pulseAccentEnabled;
|
||||
case ShellViewToggleId::NativeXCUIOverlay:
|
||||
return m_shellViewToggles.nativeXCUIOverlayVisible;
|
||||
case ShellViewToggleId::HostedPreviewHud:
|
||||
return m_shellViewToggles.hostedPreviewHudVisible;
|
||||
case ShellViewToggleId::Count:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return m_shellChromeState.GetViewToggle(toggleId);
|
||||
}
|
||||
|
||||
void Application::SetShellViewToggleEnabled(ShellViewToggleId toggleId, bool enabled) {
|
||||
switch (toggleId) {
|
||||
case ShellViewToggleId::ImGuiDemoWindow:
|
||||
m_shellViewToggles.imguiDemoWindowVisible = enabled;
|
||||
return;
|
||||
case ShellViewToggleId::NativeBackdrop:
|
||||
m_shellViewToggles.nativeBackdropVisible = enabled;
|
||||
return;
|
||||
case ShellViewToggleId::PulseAccent:
|
||||
m_shellViewToggles.pulseAccentEnabled = enabled;
|
||||
return;
|
||||
case ShellViewToggleId::NativeXCUIOverlay:
|
||||
m_shellViewToggles.nativeXCUIOverlayVisible = enabled;
|
||||
return;
|
||||
case ShellViewToggleId::HostedPreviewHud:
|
||||
m_shellViewToggles.hostedPreviewHudVisible = enabled;
|
||||
return;
|
||||
case ShellViewToggleId::Count:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
m_shellChromeState.SetViewToggle(toggleId, enabled);
|
||||
}
|
||||
|
||||
bool Application::IsNativeHostedPreviewEnabled(ShellPanelId panelId) const {
|
||||
const ShellPanelChromeState* panelState = TryGetShellPanelState(panelId);
|
||||
return panelState != nullptr &&
|
||||
panelState->hostedPreviewEnabled &&
|
||||
panelState->previewMode == ShellHostedPreviewMode::NativeOffscreen;
|
||||
return m_shellChromeState.IsNativeHostedPreviewActive(panelId);
|
||||
}
|
||||
|
||||
void Application::ConfigureHostedPreviewPresenters() {
|
||||
@@ -178,25 +129,19 @@ void Application::ConfigureShellCommandRouter() {
|
||||
|
||||
ShellCommandBindings bindings = {};
|
||||
bindings.getXCUIDemoPanelVisible = [this]() {
|
||||
const ShellPanelChromeState* panelState = TryGetShellPanelState(ShellPanelId::XCUIDemo);
|
||||
return panelState != nullptr && panelState->visible;
|
||||
return m_shellChromeState.IsPanelVisible(ShellPanelId::XCUIDemo);
|
||||
};
|
||||
bindings.setXCUIDemoPanelVisible = [this](bool visible) {
|
||||
if (ShellPanelChromeState* panelState = TryGetShellPanelState(ShellPanelId::XCUIDemo)) {
|
||||
panelState->visible = visible;
|
||||
}
|
||||
m_shellChromeState.SetPanelVisible(ShellPanelId::XCUIDemo, visible);
|
||||
if (m_demoPanel != nullptr) {
|
||||
m_demoPanel->SetVisible(visible);
|
||||
}
|
||||
};
|
||||
bindings.getXCUILayoutLabPanelVisible = [this]() {
|
||||
const ShellPanelChromeState* panelState = TryGetShellPanelState(ShellPanelId::XCUILayoutLab);
|
||||
return panelState != nullptr && panelState->visible;
|
||||
return m_shellChromeState.IsPanelVisible(ShellPanelId::XCUILayoutLab);
|
||||
};
|
||||
bindings.setXCUILayoutLabPanelVisible = [this](bool visible) {
|
||||
if (ShellPanelChromeState* panelState = TryGetShellPanelState(ShellPanelId::XCUILayoutLab)) {
|
||||
panelState->visible = visible;
|
||||
}
|
||||
m_shellChromeState.SetPanelVisible(ShellPanelId::XCUILayoutLab, visible);
|
||||
if (m_layoutLabPanel != nullptr) {
|
||||
m_layoutLabPanel->SetVisible(visible);
|
||||
}
|
||||
@@ -235,23 +180,17 @@ void Application::ConfigureShellCommandRouter() {
|
||||
return IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo);
|
||||
};
|
||||
bindings.setNativeDemoPanelPreviewEnabled = [this](bool enabled) {
|
||||
if (ShellPanelChromeState* panelState = TryGetShellPanelState(ShellPanelId::XCUIDemo)) {
|
||||
panelState->previewMode =
|
||||
enabled
|
||||
? ShellHostedPreviewMode::NativeOffscreen
|
||||
: ShellHostedPreviewMode::LegacyImGui;
|
||||
}
|
||||
m_shellChromeState.SetHostedPreviewMode(
|
||||
ShellPanelId::XCUIDemo,
|
||||
enabled ? ShellHostedPreviewMode::NativeOffscreen : ShellHostedPreviewMode::HostedPresenter);
|
||||
};
|
||||
bindings.getNativeLayoutLabPreviewEnabled = [this]() {
|
||||
return IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab);
|
||||
};
|
||||
bindings.setNativeLayoutLabPreviewEnabled = [this](bool enabled) {
|
||||
if (ShellPanelChromeState* panelState = TryGetShellPanelState(ShellPanelId::XCUILayoutLab)) {
|
||||
panelState->previewMode =
|
||||
enabled
|
||||
? ShellHostedPreviewMode::NativeOffscreen
|
||||
: ShellHostedPreviewMode::LegacyImGui;
|
||||
}
|
||||
m_shellChromeState.SetHostedPreviewMode(
|
||||
ShellPanelId::XCUILayoutLab,
|
||||
enabled ? ShellHostedPreviewMode::NativeOffscreen : ShellHostedPreviewMode::HostedPresenter);
|
||||
};
|
||||
bindings.onHostedPreviewModeChanged = [this]() { ConfigureHostedPreviewPresenters(); };
|
||||
|
||||
@@ -356,10 +295,12 @@ int Application::Run(HINSTANCE instance, int nCmdShow) {
|
||||
InitializeWindowCompositor();
|
||||
m_demoPanel = std::make_unique<XCUIDemoPanel>(
|
||||
&m_xcuiInputSource,
|
||||
CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo)));
|
||||
CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo)),
|
||||
::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost());
|
||||
m_layoutLabPanel = std::make_unique<XCUILayoutLabPanel>(
|
||||
&m_xcuiInputSource,
|
||||
CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab)));
|
||||
CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab)),
|
||||
::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost());
|
||||
ConfigureHostedPreviewPresenters();
|
||||
m_shellInputBridge.Reset();
|
||||
ConfigureShellCommandRouter();
|
||||
@@ -531,13 +472,12 @@ void Application::DestroyHostedPreviewSurfaces() {
|
||||
}
|
||||
|
||||
void Application::SyncShellChromePanelStateFromPanels() {
|
||||
if (ShellPanelChromeState* demoState = TryGetShellPanelState(ShellPanelId::XCUIDemo)) {
|
||||
demoState->visible = m_demoPanel != nullptr && m_demoPanel->IsVisible();
|
||||
}
|
||||
|
||||
if (ShellPanelChromeState* layoutLabState = TryGetShellPanelState(ShellPanelId::XCUILayoutLab)) {
|
||||
layoutLabState->visible = m_layoutLabPanel != nullptr && m_layoutLabPanel->IsVisible();
|
||||
}
|
||||
m_shellChromeState.SetPanelVisible(
|
||||
ShellPanelId::XCUIDemo,
|
||||
m_demoPanel != nullptr && m_demoPanel->IsVisible());
|
||||
m_shellChromeState.SetPanelVisible(
|
||||
ShellPanelId::XCUILayoutLab,
|
||||
m_layoutLabPanel != nullptr && m_layoutLabPanel->IsVisible());
|
||||
}
|
||||
|
||||
void Application::SyncHostedPreviewSurfaces() {
|
||||
@@ -864,14 +804,14 @@ void Application::RenderShellChrome() {
|
||||
"XCUI Demo preview: %s",
|
||||
IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo)
|
||||
? "native offscreen preview surface"
|
||||
: "ImGui hosted preview");
|
||||
: "hosted presenter");
|
||||
}
|
||||
if (m_layoutLabPanel != nullptr) {
|
||||
ImGui::TextDisabled(
|
||||
"Layout Lab preview: %s",
|
||||
IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab)
|
||||
? "native offscreen preview surface"
|
||||
: "ImGui hosted preview");
|
||||
: "hosted presenter");
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
@@ -1102,8 +1042,10 @@ void Application::Frame() {
|
||||
if (m_layoutLabPanel) {
|
||||
m_layoutLabPanel->RenderIfVisible();
|
||||
}
|
||||
if (m_shellViewToggles.imguiDemoWindowVisible) {
|
||||
ImGui::ShowDemoWindow(&m_shellViewToggles.imguiDemoWindowVisible);
|
||||
bool showImGuiDemoWindow = IsShellViewToggleEnabled(ShellViewToggleId::ImGuiDemoWindow);
|
||||
if (showImGuiDemoWindow) {
|
||||
ImGui::ShowDemoWindow(&showImGuiDemoWindow);
|
||||
SetShellViewToggleEnabled(ShellViewToggleId::ImGuiDemoWindow, showImGuiDemoWindow);
|
||||
}
|
||||
|
||||
SyncShellChromePanelStateFromPanels();
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "XCUIBackend/XCUIShellChromeState.h"
|
||||
#include "XCUIBackend/XCUIStandaloneTextAtlasProvider.h"
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
@@ -31,6 +30,7 @@ namespace NewEditor {
|
||||
|
||||
class Application {
|
||||
public:
|
||||
using ShellChromeState = ::XCEngine::Editor::XCUIBackend::XCUIShellChromeState;
|
||||
using ShellPanelId = ::XCEngine::Editor::XCUIBackend::XCUIShellPanelId;
|
||||
using ShellViewToggleId = ::XCEngine::Editor::XCUIBackend::XCUIShellViewToggleId;
|
||||
using ShellHostedPreviewMode = ::XCEngine::Editor::XCUIBackend::XCUIShellHostedPreviewMode;
|
||||
@@ -248,35 +248,6 @@ public:
|
||||
int Run(HINSTANCE instance, int nCmdShow);
|
||||
|
||||
private:
|
||||
using ShellPanelStateArray = std::array<ShellPanelChromeState, static_cast<std::size_t>(ShellPanelId::Count)>;
|
||||
|
||||
static constexpr std::size_t GetShellPanelIndex(ShellPanelId panelId) {
|
||||
return static_cast<std::size_t>(panelId);
|
||||
}
|
||||
|
||||
static ShellPanelStateArray CreateDefaultShellPanelStates() {
|
||||
ShellPanelStateArray panels = {};
|
||||
panels[GetShellPanelIndex(ShellPanelId::XCUIDemo)] = {
|
||||
ShellPanelId::XCUIDemo,
|
||||
"XCUI Demo",
|
||||
"XCUI Demo",
|
||||
"new_editor.panels.xcui_demo",
|
||||
true,
|
||||
true,
|
||||
ShellHostedPreviewMode::NativeOffscreen
|
||||
};
|
||||
panels[GetShellPanelIndex(ShellPanelId::XCUILayoutLab)] = {
|
||||
ShellPanelId::XCUILayoutLab,
|
||||
"XCUI Layout Lab",
|
||||
"XCUI Layout Lab",
|
||||
"new_editor.panels.xcui_layout_lab",
|
||||
true,
|
||||
true,
|
||||
ShellHostedPreviewMode::LegacyImGui
|
||||
};
|
||||
return panels;
|
||||
}
|
||||
|
||||
struct HostedPreviewPanelDiagnostics {
|
||||
std::string debugName = {};
|
||||
std::string debugSource = {};
|
||||
@@ -334,7 +305,6 @@ private:
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> CreateHostedPreviewPresenter(
|
||||
bool nativePreview);
|
||||
void ConfigureHostedPreviewPresenters();
|
||||
ShellPanelChromeState* TryGetShellPanelState(ShellPanelId panelId);
|
||||
const ShellPanelChromeState* TryGetShellPanelState(ShellPanelId panelId) const;
|
||||
bool IsShellViewToggleEnabled(ShellViewToggleId toggleId) const;
|
||||
void SetShellViewToggleEnabled(ShellViewToggleId toggleId, bool enabled);
|
||||
@@ -379,8 +349,7 @@ private:
|
||||
::XCEngine::Editor::XCUIBackend::XCUIHostedPreviewSurfaceRegistry m_hostedPreviewSurfaceRegistry;
|
||||
::XCEngine::Editor::XCUIBackend::XCUIStandaloneTextAtlasProvider m_hostedPreviewTextAtlasProvider;
|
||||
::XCEngine::Editor::XCUIBackend::XCUIRHIRenderBackend m_hostedPreviewRenderBackend;
|
||||
ShellViewToggleState m_shellViewToggles = {};
|
||||
ShellPanelStateArray m_shellPanels = CreateDefaultShellPanelStates();
|
||||
ShellChromeState m_shellChromeState = {};
|
||||
std::vector<HostedPreviewOffscreenSurface> m_hostedPreviewSurfaces = {};
|
||||
::XCEngine::Editor::XCUIBackend::XCUILayoutLabRuntime m_nativeOverlayRuntime;
|
||||
MainWindowNativeBackdropRenderer m_nativeBackdropRenderer;
|
||||
|
||||
56
new_editor/src/XCUIBackend/ImGuiXCUIInputSource.h
Normal file
56
new_editor/src/XCUIBackend/ImGuiXCUIInputSource.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "XCUIBackend/ImGuiXCUIInputAdapter.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace XCUIBackend {
|
||||
|
||||
class ImGuiXCUIInputSnapshotSource final : public IXCUIInputSnapshotSource {
|
||||
public:
|
||||
explicit ImGuiXCUIInputSnapshotSource(const ImGuiIO* io = nullptr)
|
||||
: m_io(io) {
|
||||
}
|
||||
|
||||
void SetIO(const ImGuiIO* io) {
|
||||
m_io = io;
|
||||
}
|
||||
|
||||
const ImGuiIO* GetIO() const {
|
||||
return ResolveIO();
|
||||
}
|
||||
|
||||
XCUIInputBridgeFrameSnapshot CaptureSnapshot(
|
||||
const XCUIInputBridgeCaptureOptions& options = XCUIInputBridgeCaptureOptions()) const override {
|
||||
const ImGuiIO* io = ResolveIO();
|
||||
return io != nullptr
|
||||
? ImGuiXCUIInputAdapter::CaptureSnapshot(*io, options)
|
||||
: XCUIInputBridgeFrameSnapshot();
|
||||
}
|
||||
|
||||
const ::XCEngine::UI::UIPoint& GetPointerPosition() const override {
|
||||
m_cachedPointerPosition = {};
|
||||
const ImGuiIO* io = ResolveIO();
|
||||
if (io != nullptr) {
|
||||
m_cachedPointerPosition = ::XCEngine::UI::UIPoint(io->MousePos.x, io->MousePos.y);
|
||||
}
|
||||
|
||||
return m_cachedPointerPosition;
|
||||
}
|
||||
|
||||
private:
|
||||
const ImGuiIO* ResolveIO() const {
|
||||
if (m_io != nullptr) {
|
||||
return m_io;
|
||||
}
|
||||
|
||||
return ImGui::GetCurrentContext() != nullptr ? &ImGui::GetIO() : nullptr;
|
||||
}
|
||||
|
||||
const ImGuiIO* m_io = nullptr;
|
||||
mutable ::XCEngine::UI::UIPoint m_cachedPointerPosition = {};
|
||||
};
|
||||
|
||||
} // namespace XCUIBackend
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
@@ -23,8 +23,8 @@ public:
|
||||
}
|
||||
|
||||
XCUIPanelCanvasSession BeginCanvas(const XCUIPanelCanvasRequest& request) override {
|
||||
(void)request;
|
||||
return {};
|
||||
m_canvasSession = BuildPassiveXCUIPanelCanvasSession(request);
|
||||
return m_canvasSession;
|
||||
}
|
||||
|
||||
void DrawFilledRect(
|
||||
@@ -59,7 +59,11 @@ public:
|
||||
}
|
||||
|
||||
void EndCanvas() override {
|
||||
m_canvasSession = {};
|
||||
}
|
||||
|
||||
private:
|
||||
XCUIPanelCanvasSession m_canvasSession = {};
|
||||
};
|
||||
|
||||
inline std::unique_ptr<IXCUIPanelCanvasHost> CreateNullXCUIPanelCanvasHost() {
|
||||
|
||||
@@ -260,6 +260,27 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class NullXCUIHostedPreviewPresenter final : public IXCUIHostedPreviewPresenter {
|
||||
public:
|
||||
bool Present(const XCUIHostedPreviewFrame& frame) override {
|
||||
m_lastStats = {};
|
||||
if (frame.drawData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lastStats.submittedDrawListCount = frame.drawData->GetDrawListCount();
|
||||
m_lastStats.submittedCommandCount = frame.drawData->GetTotalCommandCount();
|
||||
return false;
|
||||
}
|
||||
|
||||
const XCUIHostedPreviewStats& GetLastStats() const override {
|
||||
return m_lastStats;
|
||||
}
|
||||
|
||||
private:
|
||||
XCUIHostedPreviewStats m_lastStats = {};
|
||||
};
|
||||
|
||||
class QueuedNativeXCUIHostedPreviewPresenter final : public IXCUIHostedPreviewPresenter {
|
||||
public:
|
||||
QueuedNativeXCUIHostedPreviewPresenter(
|
||||
@@ -306,6 +327,10 @@ inline std::unique_ptr<IXCUIHostedPreviewPresenter> CreateQueuedNativeXCUIHosted
|
||||
return std::make_unique<QueuedNativeXCUIHostedPreviewPresenter>(queue, surfaceRegistry);
|
||||
}
|
||||
|
||||
inline std::unique_ptr<IXCUIHostedPreviewPresenter> CreateNullXCUIHostedPreviewPresenter() {
|
||||
return std::make_unique<NullXCUIHostedPreviewPresenter>();
|
||||
}
|
||||
|
||||
} // namespace XCUIBackend
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -85,6 +85,15 @@ struct XCUIInputBridgeFrameDelta {
|
||||
bool HasEventType(UI::UIInputEventType type) const;
|
||||
};
|
||||
|
||||
class IXCUIInputSnapshotSource {
|
||||
public:
|
||||
virtual ~IXCUIInputSnapshotSource() = default;
|
||||
|
||||
virtual XCUIInputBridgeFrameSnapshot CaptureSnapshot(
|
||||
const XCUIInputBridgeCaptureOptions& options = XCUIInputBridgeCaptureOptions()) const = 0;
|
||||
virtual const UI::UIPoint& GetPointerPosition() const = 0;
|
||||
};
|
||||
|
||||
class XCUIInputBridge {
|
||||
public:
|
||||
void Reset();
|
||||
@@ -109,16 +118,16 @@ private:
|
||||
XCUIInputBridgeFrameSnapshot m_baseline = {};
|
||||
};
|
||||
|
||||
class XCUIWin32InputSource {
|
||||
class XCUIWin32InputSource : public IXCUIInputSnapshotSource {
|
||||
public:
|
||||
void Reset();
|
||||
void HandleWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void ClearFrameTransients();
|
||||
|
||||
XCUIInputBridgeFrameSnapshot CaptureSnapshot(
|
||||
const XCUIInputBridgeCaptureOptions& options = XCUIInputBridgeCaptureOptions()) const;
|
||||
const XCUIInputBridgeCaptureOptions& options = XCUIInputBridgeCaptureOptions()) const override;
|
||||
|
||||
const UI::UIPoint& GetPointerPosition() const {
|
||||
const UI::UIPoint& GetPointerPosition() const override {
|
||||
return m_pointerPosition;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,36 @@ struct XCUIPanelCanvasSession {
|
||||
bool windowFocused = false;
|
||||
};
|
||||
|
||||
inline const char* ResolveXCUIPanelCanvasChildId(
|
||||
const XCUIPanelCanvasRequest& request,
|
||||
const char* fallback = "XCUIPanelCanvasHost") {
|
||||
if (request.childId != nullptr && request.childId[0] != '\0') {
|
||||
return request.childId;
|
||||
}
|
||||
|
||||
return fallback != nullptr ? fallback : "XCUIPanelCanvasHost";
|
||||
}
|
||||
|
||||
inline XCUIPanelCanvasSession BuildPassiveXCUIPanelCanvasSession(
|
||||
const XCUIPanelCanvasRequest& request) {
|
||||
const float hostHeight = request.height > 0.0f ? request.height : 0.0f;
|
||||
const float topInset = request.topInset > 0.0f ? request.topInset : 0.0f;
|
||||
const float clampedTopInset = topInset < hostHeight ? topInset : hostHeight;
|
||||
|
||||
XCUIPanelCanvasSession session = {};
|
||||
session.hostRect = ::XCEngine::UI::UIRect(0.0f, 0.0f, 0.0f, hostHeight);
|
||||
session.canvasRect = ::XCEngine::UI::UIRect(
|
||||
0.0f,
|
||||
clampedTopInset,
|
||||
0.0f,
|
||||
hostHeight - clampedTopInset);
|
||||
session.pointerPosition = {};
|
||||
session.validCanvas = false;
|
||||
session.hovered = false;
|
||||
session.windowFocused = false;
|
||||
return session;
|
||||
}
|
||||
|
||||
class IXCUIPanelCanvasHost {
|
||||
public:
|
||||
virtual ~IXCUIPanelCanvasHost() = default;
|
||||
|
||||
@@ -10,6 +10,17 @@ constexpr std::size_t ToIndex(XCUIShellPanelId panelId) {
|
||||
return static_cast<std::size_t>(panelId);
|
||||
}
|
||||
|
||||
constexpr std::string_view kViewMenuLabel = "View";
|
||||
constexpr std::string_view kXCUIDemoShortcut = "Ctrl+1";
|
||||
constexpr std::string_view kXCUILayoutLabShortcut = "Ctrl+2";
|
||||
constexpr std::string_view kImGuiDemoShortcut = "Ctrl+3";
|
||||
constexpr std::string_view kNativeBackdropShortcut = "Ctrl+Shift+B";
|
||||
constexpr std::string_view kPulseAccentShortcut = "Ctrl+Shift+P";
|
||||
constexpr std::string_view kNativeXCUIOverlayShortcut = "Ctrl+Shift+O";
|
||||
constexpr std::string_view kHostedPreviewHudShortcut = "Ctrl+Shift+H";
|
||||
constexpr std::string_view kNativeDemoPanelPreviewShortcut = "Ctrl+Alt+1";
|
||||
constexpr std::string_view kNativeLayoutLabPreviewShortcut = "Ctrl+Alt+2";
|
||||
|
||||
} // namespace
|
||||
|
||||
XCUIShellChromeState::XCUIShellChromeState() {
|
||||
@@ -29,7 +40,7 @@ XCUIShellChromeState::XCUIShellChromeState() {
|
||||
"new_editor.panels.xcui_layout_lab",
|
||||
true,
|
||||
true,
|
||||
XCUIShellHostedPreviewMode::LegacyImGui
|
||||
XCUIShellHostedPreviewMode::HostedPresenter
|
||||
};
|
||||
}
|
||||
|
||||
@@ -104,7 +115,7 @@ XCUIShellHostedPreviewMode XCUIShellChromeState::GetHostedPreviewMode(XCUIShellP
|
||||
const XCUIShellPanelChromeState* panelState = TryGetPanelState(panelId);
|
||||
return panelState != nullptr
|
||||
? panelState->previewMode
|
||||
: XCUIShellHostedPreviewMode::LegacyImGui;
|
||||
: XCUIShellHostedPreviewMode::HostedPresenter;
|
||||
}
|
||||
|
||||
XCUIShellHostedPreviewState XCUIShellChromeState::GetHostedPreviewState(XCUIShellPanelId panelId) const {
|
||||
@@ -115,15 +126,15 @@ XCUIShellHostedPreviewState XCUIShellChromeState::GetHostedPreviewState(XCUIShel
|
||||
|
||||
return panelState->previewMode == XCUIShellHostedPreviewMode::NativeOffscreen
|
||||
? XCUIShellHostedPreviewState::NativeOffscreen
|
||||
: XCUIShellHostedPreviewState::LegacyImGui;
|
||||
: XCUIShellHostedPreviewState::HostedPresenter;
|
||||
}
|
||||
|
||||
bool XCUIShellChromeState::IsNativeHostedPreviewActive(XCUIShellPanelId panelId) const {
|
||||
return GetHostedPreviewState(panelId) == XCUIShellHostedPreviewState::NativeOffscreen;
|
||||
}
|
||||
|
||||
bool XCUIShellChromeState::IsLegacyHostedPreviewActive(XCUIShellPanelId panelId) const {
|
||||
return GetHostedPreviewState(panelId) == XCUIShellHostedPreviewState::LegacyImGui;
|
||||
bool XCUIShellChromeState::IsHostedPresenterPreviewActive(XCUIShellPanelId panelId) const {
|
||||
return GetHostedPreviewState(panelId) == XCUIShellHostedPreviewState::HostedPresenter;
|
||||
}
|
||||
|
||||
bool XCUIShellChromeState::SetHostedPreviewMode(
|
||||
@@ -146,7 +157,7 @@ bool XCUIShellChromeState::ToggleHostedPreviewMode(XCUIShellPanelId panelId) {
|
||||
|
||||
panelState->previewMode =
|
||||
panelState->previewMode == XCUIShellHostedPreviewMode::NativeOffscreen
|
||||
? XCUIShellHostedPreviewMode::LegacyImGui
|
||||
? XCUIShellHostedPreviewMode::HostedPresenter
|
||||
: XCUIShellHostedPreviewMode::NativeOffscreen;
|
||||
return true;
|
||||
}
|
||||
@@ -205,15 +216,8 @@ bool XCUIShellChromeState::ToggleViewToggle(XCUIShellViewToggleId toggleId) {
|
||||
}
|
||||
|
||||
bool XCUIShellChromeState::HasCommand(std::string_view commandId) const {
|
||||
return commandId == GetPanelVisibilityCommandId(XCUIShellPanelId::XCUIDemo) ||
|
||||
commandId == GetPanelVisibilityCommandId(XCUIShellPanelId::XCUILayoutLab) ||
|
||||
commandId == GetViewToggleCommandId(XCUIShellViewToggleId::ImGuiDemoWindow) ||
|
||||
commandId == GetViewToggleCommandId(XCUIShellViewToggleId::NativeBackdrop) ||
|
||||
commandId == GetViewToggleCommandId(XCUIShellViewToggleId::PulseAccent) ||
|
||||
commandId == GetViewToggleCommandId(XCUIShellViewToggleId::NativeXCUIOverlay) ||
|
||||
commandId == GetViewToggleCommandId(XCUIShellViewToggleId::HostedPreviewHud) ||
|
||||
commandId == GetPanelPreviewModeCommandId(XCUIShellPanelId::XCUIDemo) ||
|
||||
commandId == GetPanelPreviewModeCommandId(XCUIShellPanelId::XCUILayoutLab);
|
||||
XCUIShellCommandDescriptor descriptor = {};
|
||||
return TryGetCommandDescriptor(commandId, descriptor);
|
||||
}
|
||||
|
||||
bool XCUIShellChromeState::InvokeCommand(std::string_view commandId) {
|
||||
@@ -248,6 +252,142 @@ bool XCUIShellChromeState::InvokeCommand(std::string_view commandId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool XCUIShellChromeState::TryGetCommandDescriptor(
|
||||
std::string_view commandId,
|
||||
XCUIShellCommandDescriptor& outDescriptor) const {
|
||||
outDescriptor = {};
|
||||
outDescriptor.checkable = false;
|
||||
outDescriptor.enabled = false;
|
||||
|
||||
const auto tryBuildPanelVisibilityDescriptor =
|
||||
[this, commandId, &outDescriptor](
|
||||
XCUIShellPanelId panelId,
|
||||
std::string_view shortcut) {
|
||||
if (commandId != GetPanelVisibilityCommandId(panelId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const XCUIShellPanelChromeState* panelState = TryGetPanelState(panelId);
|
||||
if (panelState == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outDescriptor.label = panelState->panelTitle;
|
||||
outDescriptor.shortcut = shortcut;
|
||||
outDescriptor.commandId = commandId;
|
||||
outDescriptor.checkable = true;
|
||||
outDescriptor.checked = panelState->visible;
|
||||
outDescriptor.enabled = true;
|
||||
return true;
|
||||
};
|
||||
|
||||
if (tryBuildPanelVisibilityDescriptor(XCUIShellPanelId::XCUIDemo, kXCUIDemoShortcut)) {
|
||||
return true;
|
||||
}
|
||||
if (tryBuildPanelVisibilityDescriptor(XCUIShellPanelId::XCUILayoutLab, kXCUILayoutLabShortcut)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (commandId == GetViewToggleCommandId(XCUIShellViewToggleId::ImGuiDemoWindow)) {
|
||||
outDescriptor.label = "ImGui Demo";
|
||||
outDescriptor.shortcut = kImGuiDemoShortcut;
|
||||
outDescriptor.commandId = commandId;
|
||||
outDescriptor.checkable = true;
|
||||
outDescriptor.checked = GetViewToggle(XCUIShellViewToggleId::ImGuiDemoWindow);
|
||||
outDescriptor.enabled = true;
|
||||
return true;
|
||||
}
|
||||
if (commandId == GetViewToggleCommandId(XCUIShellViewToggleId::NativeBackdrop)) {
|
||||
outDescriptor.label = "Native Backdrop";
|
||||
outDescriptor.shortcut = kNativeBackdropShortcut;
|
||||
outDescriptor.commandId = commandId;
|
||||
outDescriptor.checkable = true;
|
||||
outDescriptor.checked = GetViewToggle(XCUIShellViewToggleId::NativeBackdrop);
|
||||
outDescriptor.enabled = true;
|
||||
return true;
|
||||
}
|
||||
if (commandId == GetViewToggleCommandId(XCUIShellViewToggleId::PulseAccent)) {
|
||||
outDescriptor.label = "Pulse Accent";
|
||||
outDescriptor.shortcut = kPulseAccentShortcut;
|
||||
outDescriptor.commandId = commandId;
|
||||
outDescriptor.checkable = true;
|
||||
outDescriptor.checked = GetViewToggle(XCUIShellViewToggleId::PulseAccent);
|
||||
outDescriptor.enabled = true;
|
||||
return true;
|
||||
}
|
||||
if (commandId == GetViewToggleCommandId(XCUIShellViewToggleId::NativeXCUIOverlay)) {
|
||||
outDescriptor.label = "Native XCUI Overlay";
|
||||
outDescriptor.shortcut = kNativeXCUIOverlayShortcut;
|
||||
outDescriptor.commandId = commandId;
|
||||
outDescriptor.checkable = true;
|
||||
outDescriptor.checked = GetViewToggle(XCUIShellViewToggleId::NativeXCUIOverlay);
|
||||
outDescriptor.enabled = true;
|
||||
return true;
|
||||
}
|
||||
if (commandId == GetViewToggleCommandId(XCUIShellViewToggleId::HostedPreviewHud)) {
|
||||
outDescriptor.label = "Hosted Preview HUD";
|
||||
outDescriptor.shortcut = kHostedPreviewHudShortcut;
|
||||
outDescriptor.commandId = commandId;
|
||||
outDescriptor.checkable = true;
|
||||
outDescriptor.checked = GetViewToggle(XCUIShellViewToggleId::HostedPreviewHud);
|
||||
outDescriptor.enabled = true;
|
||||
return true;
|
||||
}
|
||||
if (commandId == GetPanelPreviewModeCommandId(XCUIShellPanelId::XCUIDemo)) {
|
||||
outDescriptor.label = "Native Demo Panel Preview";
|
||||
outDescriptor.shortcut = kNativeDemoPanelPreviewShortcut;
|
||||
outDescriptor.commandId = commandId;
|
||||
outDescriptor.checkable = true;
|
||||
outDescriptor.checked = IsNativeHostedPreviewActive(XCUIShellPanelId::XCUIDemo);
|
||||
outDescriptor.enabled = true;
|
||||
return true;
|
||||
}
|
||||
if (commandId == GetPanelPreviewModeCommandId(XCUIShellPanelId::XCUILayoutLab)) {
|
||||
outDescriptor.label = "Native Layout Lab Preview";
|
||||
outDescriptor.shortcut = kNativeLayoutLabPreviewShortcut;
|
||||
outDescriptor.commandId = commandId;
|
||||
outDescriptor.checkable = true;
|
||||
outDescriptor.checked = IsNativeHostedPreviewActive(XCUIShellPanelId::XCUILayoutLab);
|
||||
outDescriptor.enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
XCUIShellMenuDescriptor XCUIShellChromeState::BuildViewMenuDescriptor() const {
|
||||
XCUIShellMenuDescriptor descriptor = {};
|
||||
descriptor.label = kViewMenuLabel;
|
||||
descriptor.items.reserve(10u);
|
||||
|
||||
const auto appendCommandItem = [this, &descriptor](std::string_view commandId) {
|
||||
XCUIShellCommandDescriptor commandDescriptor = {};
|
||||
if (!TryGetCommandDescriptor(commandId, commandDescriptor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
XCUIShellMenuItemDescriptor item = {};
|
||||
item.kind = XCUIShellMenuItemKind::Command;
|
||||
item.command = commandDescriptor;
|
||||
descriptor.items.push_back(item);
|
||||
};
|
||||
|
||||
appendCommandItem(GetPanelVisibilityCommandId(XCUIShellPanelId::XCUIDemo));
|
||||
appendCommandItem(GetPanelVisibilityCommandId(XCUIShellPanelId::XCUILayoutLab));
|
||||
appendCommandItem(GetViewToggleCommandId(XCUIShellViewToggleId::ImGuiDemoWindow));
|
||||
|
||||
descriptor.items.push_back({ XCUIShellMenuItemKind::Separator, {} });
|
||||
|
||||
appendCommandItem(GetViewToggleCommandId(XCUIShellViewToggleId::NativeBackdrop));
|
||||
appendCommandItem(GetViewToggleCommandId(XCUIShellViewToggleId::PulseAccent));
|
||||
appendCommandItem(GetViewToggleCommandId(XCUIShellViewToggleId::NativeXCUIOverlay));
|
||||
appendCommandItem(GetViewToggleCommandId(XCUIShellViewToggleId::HostedPreviewHud));
|
||||
appendCommandItem(GetPanelPreviewModeCommandId(XCUIShellPanelId::XCUIDemo));
|
||||
appendCommandItem(GetPanelPreviewModeCommandId(XCUIShellPanelId::XCUILayoutLab));
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
std::string_view XCUIShellChromeState::GetPanelVisibilityCommandId(XCUIShellPanelId panelId) {
|
||||
switch (panelId) {
|
||||
case XCUIShellPanelId::XCUIDemo:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
@@ -24,13 +25,13 @@ enum class XCUIShellViewToggleId : std::uint8_t {
|
||||
};
|
||||
|
||||
enum class XCUIShellHostedPreviewMode : std::uint8_t {
|
||||
LegacyImGui = 0,
|
||||
HostedPresenter = 0,
|
||||
NativeOffscreen
|
||||
};
|
||||
|
||||
enum class XCUIShellHostedPreviewState : std::uint8_t {
|
||||
Disabled = 0,
|
||||
LegacyImGui,
|
||||
HostedPresenter,
|
||||
NativeOffscreen
|
||||
};
|
||||
|
||||
@@ -41,7 +42,7 @@ struct XCUIShellPanelChromeState {
|
||||
std::string_view previewDebugSource = {};
|
||||
bool visible = true;
|
||||
bool hostedPreviewEnabled = true;
|
||||
XCUIShellHostedPreviewMode previewMode = XCUIShellHostedPreviewMode::LegacyImGui;
|
||||
XCUIShellHostedPreviewMode previewMode = XCUIShellHostedPreviewMode::HostedPresenter;
|
||||
};
|
||||
|
||||
struct XCUIShellViewToggleState {
|
||||
@@ -64,6 +65,30 @@ struct XCUIShellChromeCommandIds {
|
||||
static constexpr const char* ToggleNativeLayoutLabPreview = "new_editor.view.native_layout_lab_preview";
|
||||
};
|
||||
|
||||
enum class XCUIShellMenuItemKind : std::uint8_t {
|
||||
Command = 0,
|
||||
Separator
|
||||
};
|
||||
|
||||
struct XCUIShellCommandDescriptor {
|
||||
std::string_view label = {};
|
||||
std::string_view shortcut = {};
|
||||
std::string_view commandId = {};
|
||||
bool checkable = true;
|
||||
bool checked = false;
|
||||
bool enabled = true;
|
||||
};
|
||||
|
||||
struct XCUIShellMenuItemDescriptor {
|
||||
XCUIShellMenuItemKind kind = XCUIShellMenuItemKind::Command;
|
||||
XCUIShellCommandDescriptor command = {};
|
||||
};
|
||||
|
||||
struct XCUIShellMenuDescriptor {
|
||||
std::string_view label = {};
|
||||
std::vector<XCUIShellMenuItemDescriptor> items = {};
|
||||
};
|
||||
|
||||
class XCUIShellChromeState {
|
||||
public:
|
||||
XCUIShellChromeState();
|
||||
@@ -82,7 +107,7 @@ public:
|
||||
XCUIShellHostedPreviewMode GetHostedPreviewMode(XCUIShellPanelId panelId) const;
|
||||
XCUIShellHostedPreviewState GetHostedPreviewState(XCUIShellPanelId panelId) const;
|
||||
bool IsNativeHostedPreviewActive(XCUIShellPanelId panelId) const;
|
||||
bool IsLegacyHostedPreviewActive(XCUIShellPanelId panelId) const;
|
||||
bool IsHostedPresenterPreviewActive(XCUIShellPanelId panelId) const;
|
||||
bool SetHostedPreviewMode(XCUIShellPanelId panelId, XCUIShellHostedPreviewMode mode);
|
||||
bool ToggleHostedPreviewMode(XCUIShellPanelId panelId);
|
||||
|
||||
@@ -92,6 +117,10 @@ public:
|
||||
|
||||
bool HasCommand(std::string_view commandId) const;
|
||||
bool InvokeCommand(std::string_view commandId);
|
||||
bool TryGetCommandDescriptor(
|
||||
std::string_view commandId,
|
||||
XCUIShellCommandDescriptor& outDescriptor) const;
|
||||
XCUIShellMenuDescriptor BuildViewMenuDescriptor() const;
|
||||
|
||||
static std::string_view GetPanelVisibilityCommandId(XCUIShellPanelId panelId);
|
||||
static std::string_view GetPanelPreviewModeCommandId(XCUIShellPanelId panelId);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "XCUIDemoPanel.h"
|
||||
|
||||
#include "XCUIBackend/ImGuiXCUIHostedPreviewPresenter.h"
|
||||
#include "XCUIBackend/ImGuiXCUIPanelCanvasHost.h"
|
||||
#include "XCUIBackend/ImGuiXCUIInputAdapter.h"
|
||||
#include "XCUIBackend/NullXCUIPanelCanvasHost.h"
|
||||
|
||||
#include <XCEngine/UI/Types.h>
|
||||
|
||||
@@ -55,15 +53,27 @@ void DrawRectOverlay(
|
||||
}
|
||||
}
|
||||
|
||||
const char* GetPreviewPathLabel(bool nativeHostedPreview) {
|
||||
return nativeHostedPreview ? "native queued offscreen surface" : "legacy imgui transition";
|
||||
const char* GetPreviewPathLabel(
|
||||
const ::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter* previewPresenter) {
|
||||
if (previewPresenter == nullptr) {
|
||||
return "not injected";
|
||||
}
|
||||
|
||||
return previewPresenter->IsNativeQueued()
|
||||
? "native queued offscreen surface"
|
||||
: "hosted presenter";
|
||||
}
|
||||
|
||||
const char* GetPreviewStateLabel(
|
||||
bool nativeHostedPreview,
|
||||
const ::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter* previewPresenter,
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIHostedPreviewStats& previewStats,
|
||||
bool hasHostedSurfaceDescriptor,
|
||||
bool showHostedSurfaceImage) {
|
||||
if (previewPresenter == nullptr) {
|
||||
return "disabled";
|
||||
}
|
||||
|
||||
const bool nativeHostedPreview = previewPresenter->IsNativeQueued();
|
||||
if (nativeHostedPreview) {
|
||||
if (showHostedSurfaceImage) {
|
||||
return "live";
|
||||
@@ -77,20 +87,37 @@ const char* GetPreviewStateLabel(
|
||||
return previewStats.presented ? "live" : "idle";
|
||||
}
|
||||
|
||||
::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;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
XCUIDemoPanel::XCUIDemoPanel(::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* inputSource)
|
||||
: XCUIDemoPanel(inputSource, ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIHostedPreviewPresenter()) {}
|
||||
XCUIDemoPanel::XCUIDemoPanel(::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* inputSource)
|
||||
: XCUIDemoPanel(
|
||||
inputSource,
|
||||
nullptr,
|
||||
::XCEngine::Editor::XCUIBackend::CreateNullXCUIPanelCanvasHost()) {}
|
||||
|
||||
XCUIDemoPanel::XCUIDemoPanel(
|
||||
::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* inputSource,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> previewPresenter)
|
||||
::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* inputSource,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> previewPresenter,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost> canvasHost)
|
||||
: Panel("XCUI Demo")
|
||||
, m_inputSource(inputSource)
|
||||
, m_previewPresenter(std::move(previewPresenter))
|
||||
, m_canvasHost(::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost()) {
|
||||
if (m_previewPresenter == nullptr) {
|
||||
m_previewPresenter = ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIHostedPreviewPresenter();
|
||||
, m_canvasHost(std::move(canvasHost)) {
|
||||
if (m_canvasHost == nullptr) {
|
||||
m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateNullXCUIPanelCanvasHost();
|
||||
}
|
||||
m_lastReloadSucceeded = m_runtime.ReloadDocuments();
|
||||
}
|
||||
@@ -113,9 +140,6 @@ const ::XCEngine::Editor::XCUIBackend::XCUIHostedPreviewStats& XCUIDemoPanel::Ge
|
||||
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 = {};
|
||||
}
|
||||
|
||||
@@ -123,7 +147,7 @@ void XCUIDemoPanel::SetCanvasHost(
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost> canvasHost) {
|
||||
m_canvasHost = std::move(canvasHost);
|
||||
if (m_canvasHost == nullptr) {
|
||||
m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost();
|
||||
m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateNullXCUIPanelCanvasHost();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +184,7 @@ void XCUIDemoPanel::Render() {
|
||||
const float canvasHeight = (std::max)(140.0f, hostRegion.y - diagnosticsHeight);
|
||||
|
||||
if (m_canvasHost == nullptr) {
|
||||
m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost();
|
||||
m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateNullXCUIPanelCanvasHost();
|
||||
}
|
||||
|
||||
const bool nativeHostedPreview = IsUsingNativeHostedPreview();
|
||||
@@ -174,7 +198,7 @@ void XCUIDemoPanel::Render() {
|
||||
nativeHostedPreview &&
|
||||
m_previewPresenter != nullptr &&
|
||||
m_previewPresenter->TryGetSurfaceImage(kPreviewDebugName, hostedSurfaceImage);
|
||||
const char* const previewPathLabel = GetPreviewPathLabel(nativeHostedPreview);
|
||||
const char* const previewPathLabel = GetPreviewPathLabel(m_previewPresenter.get());
|
||||
const float topInset = m_showCanvasHud ? (kCanvasHudHeight + kCanvasHudPadding) : 0.0f;
|
||||
::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasRequest canvasRequest = {};
|
||||
canvasRequest.childId = "XCUIDemoCanvasHost";
|
||||
@@ -183,11 +207,11 @@ void XCUIDemoPanel::Render() {
|
||||
canvasRequest.showSurfaceImage = showHostedSurfaceImage;
|
||||
canvasRequest.surfaceImage = hostedSurfaceImage;
|
||||
canvasRequest.placeholderTitle =
|
||||
nativeHostedPreview ? "Native XCUI preview pending" : "Legacy XCUI canvas host";
|
||||
nativeHostedPreview ? "Native XCUI preview pending" : "Injected XCUI canvas host";
|
||||
canvasRequest.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.";
|
||||
: "Inject a concrete canvas host to render the demo sandbox inside this panel.";
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasSession canvasSession =
|
||||
m_canvasHost->BeginCanvas(canvasRequest);
|
||||
const UI::UIRect canvasRect = canvasSession.canvasRect;
|
||||
@@ -211,10 +235,7 @@ void XCUIDemoPanel::Render() {
|
||||
bridgeOptions.hasPointerInsideOverride = true;
|
||||
bridgeOptions.pointerInsideOverride = validCanvas && canvasSession.hovered;
|
||||
bridgeOptions.windowFocused = canvasSession.windowFocused;
|
||||
snapshot = ::XCEngine::Editor::XCUIBackend::ImGuiXCUIInputAdapter::CaptureSnapshot(
|
||||
ImGui::GetIO(),
|
||||
bridgeOptions);
|
||||
snapshot.pointerPosition = canvasSession.pointerPosition;
|
||||
snapshot = BuildPassiveSnapshot(canvasSession, bridgeOptions);
|
||||
}
|
||||
|
||||
if (!m_inputBridge.HasBaseline()) {
|
||||
@@ -253,7 +274,7 @@ void XCUIDemoPanel::Render() {
|
||||
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIDemoFrameStats& stats = frame.stats;
|
||||
const char* const previewStateLabel = GetPreviewStateLabel(
|
||||
nativeHostedPreview,
|
||||
m_previewPresenter.get(),
|
||||
m_lastPreviewStats,
|
||||
hasHostedSurfaceDescriptor,
|
||||
showHostedSurfaceImage);
|
||||
|
||||
@@ -15,10 +15,11 @@ namespace NewEditor {
|
||||
class XCUIDemoPanel : public Panel {
|
||||
public:
|
||||
explicit XCUIDemoPanel(
|
||||
::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* inputSource = nullptr);
|
||||
::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* inputSource = nullptr);
|
||||
XCUIDemoPanel(
|
||||
::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* inputSource,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> previewPresenter);
|
||||
::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* inputSource,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> previewPresenter,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost> canvasHost = nullptr);
|
||||
~XCUIDemoPanel() override = default;
|
||||
|
||||
void Render() override;
|
||||
@@ -37,7 +38,7 @@ private:
|
||||
bool m_hostedPreviewEnabled = true;
|
||||
bool m_showCanvasHud = true;
|
||||
bool m_showDebugRects = true;
|
||||
::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* m_inputSource = nullptr;
|
||||
::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* m_inputSource = nullptr;
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridge m_inputBridge;
|
||||
::XCEngine::Editor::XCUIBackend::XCUIDemoRuntime m_runtime;
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> m_previewPresenter;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#include "XCUILayoutLabPanel.h"
|
||||
|
||||
#include "XCUIBackend/ImGuiXCUIHostedPreviewPresenter.h"
|
||||
#include "XCUIBackend/ImGuiXCUIPanelCanvasHost.h"
|
||||
#include "XCUIBackend/NullXCUIPanelCanvasHost.h"
|
||||
#include <XCEngine/UI/Types.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -24,15 +25,27 @@ bool ContainsPoint(const UI::UIRect& rect, const UI::UIPoint& point) {
|
||||
point.y <= rect.y + rect.height;
|
||||
}
|
||||
|
||||
const char* GetPreviewPathLabel(bool nativeHostedPreview) {
|
||||
return nativeHostedPreview ? "native queued offscreen surface" : "legacy imgui transition";
|
||||
const char* GetPreviewPathLabel(
|
||||
const ::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter* previewPresenter) {
|
||||
if (previewPresenter == nullptr) {
|
||||
return "not injected";
|
||||
}
|
||||
|
||||
return previewPresenter->IsNativeQueued()
|
||||
? "native queued offscreen surface"
|
||||
: "hosted presenter";
|
||||
}
|
||||
|
||||
const char* GetPreviewStateLabel(
|
||||
bool nativeHostedPreview,
|
||||
const ::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter* previewPresenter,
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIHostedPreviewStats& previewStats,
|
||||
bool hasHostedSurfaceDescriptor,
|
||||
bool showHostedSurfaceImage) {
|
||||
if (previewPresenter == nullptr) {
|
||||
return "disabled";
|
||||
}
|
||||
|
||||
const bool nativeHostedPreview = previewPresenter->IsNativeQueued();
|
||||
if (nativeHostedPreview) {
|
||||
if (showHostedSurfaceImage) {
|
||||
return "live";
|
||||
@@ -46,6 +59,12 @@ const char* GetPreviewStateLabel(
|
||||
return previewStats.presented ? "live" : "idle";
|
||||
}
|
||||
|
||||
bool ContainsKeyTransition(
|
||||
const std::vector<std::int32_t>& keys,
|
||||
std::int32_t keyCode) {
|
||||
return std::find(keys.begin(), keys.end(), keyCode) != keys.end();
|
||||
}
|
||||
|
||||
bool ShouldCaptureKeyboardNavigation(
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasSession& canvasSession,
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUILayoutLabFrameResult& previousFrame) {
|
||||
@@ -60,33 +79,56 @@ bool ShouldCaptureKeyboardNavigation(
|
||||
|
||||
void PopulateKeyboardNavigationInput(
|
||||
::XCEngine::Editor::XCUIBackend::XCUILayoutLabInputState& input,
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta& frameDelta,
|
||||
bool captureKeyboardNavigation) {
|
||||
if (!captureKeyboardNavigation) {
|
||||
return;
|
||||
}
|
||||
|
||||
input.navigatePrevious = ImGui::IsKeyPressed(ImGuiKey_UpArrow);
|
||||
input.navigateNext = ImGui::IsKeyPressed(ImGuiKey_DownArrow);
|
||||
input.navigateHome = ImGui::IsKeyPressed(ImGuiKey_Home);
|
||||
input.navigateEnd = ImGui::IsKeyPressed(ImGuiKey_End);
|
||||
input.navigateCollapse = ImGui::IsKeyPressed(ImGuiKey_LeftArrow);
|
||||
input.navigateExpand = ImGui::IsKeyPressed(ImGuiKey_RightArrow);
|
||||
using ::XCEngine::Input::KeyCode;
|
||||
const auto pressedThisFrame =
|
||||
[&frameDelta](KeyCode keyCode) {
|
||||
const std::int32_t code = static_cast<std::int32_t>(keyCode);
|
||||
return ContainsKeyTransition(frameDelta.keyboard.pressedKeys, code) ||
|
||||
ContainsKeyTransition(frameDelta.keyboard.repeatedKeys, code);
|
||||
};
|
||||
|
||||
input.navigatePrevious = pressedThisFrame(KeyCode::Up);
|
||||
input.navigateNext = pressedThisFrame(KeyCode::Down);
|
||||
input.navigateHome = pressedThisFrame(KeyCode::Home);
|
||||
input.navigateEnd = pressedThisFrame(KeyCode::End);
|
||||
input.navigateCollapse = pressedThisFrame(KeyCode::Left);
|
||||
input.navigateExpand = pressedThisFrame(KeyCode::Right);
|
||||
}
|
||||
|
||||
::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;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
XCUILayoutLabPanel::XCUILayoutLabPanel(::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* inputSource)
|
||||
: XCUILayoutLabPanel(inputSource, ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIHostedPreviewPresenter()) {}
|
||||
XCUILayoutLabPanel::XCUILayoutLabPanel(::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* inputSource)
|
||||
: XCUILayoutLabPanel(inputSource, nullptr, ::XCEngine::Editor::XCUIBackend::CreateNullXCUIPanelCanvasHost()) {}
|
||||
|
||||
XCUILayoutLabPanel::XCUILayoutLabPanel(
|
||||
::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* inputSource,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> previewPresenter)
|
||||
::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* inputSource,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> previewPresenter,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost> canvasHost)
|
||||
: Panel("XCUI Layout Lab")
|
||||
, m_inputSource(inputSource)
|
||||
, m_previewPresenter(std::move(previewPresenter))
|
||||
, m_canvasHost(::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost()) {
|
||||
if (m_previewPresenter == nullptr) {
|
||||
m_previewPresenter = ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIHostedPreviewPresenter();
|
||||
, m_canvasHost(std::move(canvasHost)) {
|
||||
if (m_canvasHost == nullptr) {
|
||||
m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateNullXCUIPanelCanvasHost();
|
||||
}
|
||||
m_lastReloadSucceeded = m_runtime.ReloadDocuments();
|
||||
}
|
||||
@@ -113,9 +155,6 @@ bool XCUILayoutLabPanel::TryGetElementRect(const std::string& elementId, ::XCEng
|
||||
void XCUILayoutLabPanel::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 = {};
|
||||
}
|
||||
|
||||
@@ -123,7 +162,7 @@ void XCUILayoutLabPanel::SetCanvasHost(
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost> canvasHost) {
|
||||
m_canvasHost = std::move(canvasHost);
|
||||
if (m_canvasHost == nullptr) {
|
||||
m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost();
|
||||
m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateNullXCUIPanelCanvasHost();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +195,7 @@ void XCUILayoutLabPanel::Render() {
|
||||
const float canvasHeight = (std::max)(140.0f, hostRegion.y - diagnosticsHeight);
|
||||
|
||||
if (m_canvasHost == nullptr) {
|
||||
m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost();
|
||||
m_canvasHost = ::XCEngine::Editor::XCUIBackend::CreateNullXCUIPanelCanvasHost();
|
||||
}
|
||||
|
||||
const bool nativeHostedPreview = IsUsingNativeHostedPreview();
|
||||
@@ -170,18 +209,18 @@ void XCUILayoutLabPanel::Render() {
|
||||
nativeHostedPreview &&
|
||||
m_previewPresenter != nullptr &&
|
||||
m_previewPresenter->TryGetSurfaceImage(kPreviewDebugName, hostedSurfaceImage);
|
||||
const char* const previewPathLabel = GetPreviewPathLabel(nativeHostedPreview);
|
||||
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" : "Legacy layout canvas host";
|
||||
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."
|
||||
: "Legacy ImGui transition path remains active until native offscreen preview is enabled.";
|
||||
: "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 =
|
||||
@@ -189,18 +228,40 @@ void XCUILayoutLabPanel::Render() {
|
||||
const UI::UIRect canvasRect = canvasSession.canvasRect;
|
||||
const bool validCanvas = canvasSession.validCanvas;
|
||||
|
||||
::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());
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot snapshot = {};
|
||||
if (m_inputSource != nullptr) {
|
||||
bridgeOptions.hasPointerInsideOverride = true;
|
||||
bridgeOptions.windowFocused = canvasSession.windowFocused;
|
||||
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 && canvasSession.hovered;
|
||||
bridgeOptions.windowFocused = canvasSession.windowFocused;
|
||||
snapshot = BuildPassiveSnapshot(canvasSession, bridgeOptions);
|
||||
}
|
||||
|
||||
if (!m_inputBridge.HasBaseline()) {
|
||||
m_inputBridge.Prime(snapshot);
|
||||
}
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta frameDelta =
|
||||
m_inputBridge.Translate(snapshot);
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUILayoutLabInputState input = {};
|
||||
input.canvasRect = canvasRect;
|
||||
if (m_inputSource != nullptr) {
|
||||
input.pointerPosition = m_inputSource->GetPointerPosition();
|
||||
input.pointerInside = validCanvas && ContainsPoint(input.canvasRect, input.pointerPosition);
|
||||
} else {
|
||||
input.pointerPosition = canvasSession.pointerPosition;
|
||||
input.pointerInside = validCanvas && canvasSession.hovered;
|
||||
}
|
||||
input.pointerPressed = input.pointerInside && ImGui::IsMouseClicked(ImGuiMouseButton_Left);
|
||||
input.pointerPosition = snapshot.pointerPosition;
|
||||
input.pointerInside = snapshot.pointerInside;
|
||||
input.pointerPressed = input.pointerInside && frameDelta.pointer.pressed[0];
|
||||
PopulateKeyboardNavigationInput(
|
||||
input,
|
||||
frameDelta,
|
||||
ShouldCaptureKeyboardNavigation(canvasSession, m_runtime.GetFrameResult()));
|
||||
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUILayoutLabFrameResult& frame = m_runtime.Update(input);
|
||||
@@ -220,7 +281,7 @@ void XCUILayoutLabPanel::Render() {
|
||||
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUILayoutLabFrameStats& stats = frame.stats;
|
||||
const char* const previewStateLabel = GetPreviewStateLabel(
|
||||
nativeHostedPreview,
|
||||
m_previewPresenter.get(),
|
||||
m_lastPreviewStats,
|
||||
hasHostedSurfaceDescriptor,
|
||||
showHostedSurfaceImage);
|
||||
@@ -266,7 +327,7 @@ void XCUILayoutLabPanel::Render() {
|
||||
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::TextDisabled("No native surface descriptor is available without a native queued presenter.");
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Runtime");
|
||||
|
||||
@@ -16,10 +16,11 @@ namespace NewEditor {
|
||||
class XCUILayoutLabPanel : public Panel {
|
||||
public:
|
||||
explicit XCUILayoutLabPanel(
|
||||
::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* inputSource = nullptr);
|
||||
::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* inputSource = nullptr);
|
||||
XCUILayoutLabPanel(
|
||||
::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* inputSource,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> previewPresenter);
|
||||
::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* inputSource,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> previewPresenter,
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost> canvasHost = nullptr);
|
||||
~XCUILayoutLabPanel() override = default;
|
||||
|
||||
void Render() override;
|
||||
@@ -37,7 +38,8 @@ public:
|
||||
private:
|
||||
bool m_lastReloadSucceeded = false;
|
||||
bool m_hostedPreviewEnabled = true;
|
||||
::XCEngine::Editor::XCUIBackend::XCUIWin32InputSource* m_inputSource = nullptr;
|
||||
::XCEngine::Editor::XCUIBackend::IXCUIInputSnapshotSource* m_inputSource = nullptr;
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridge m_inputBridge;
|
||||
::XCEngine::Editor::XCUIBackend::XCUILayoutLabRuntime m_runtime;
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> m_previewPresenter;
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost> m_canvasHost;
|
||||
|
||||
@@ -46,6 +46,12 @@ set(NEW_EDITOR_LAYOUT_LAB_PANEL_HEADER
|
||||
set(NEW_EDITOR_LAYOUT_LAB_PANEL_SOURCE
|
||||
${CMAKE_SOURCE_DIR}/new_editor/src/panels/XCUILayoutLabPanel.cpp
|
||||
)
|
||||
set(NEW_EDITOR_DEMO_PANEL_HEADER
|
||||
${CMAKE_SOURCE_DIR}/new_editor/src/panels/XCUIDemoPanel.h
|
||||
)
|
||||
set(NEW_EDITOR_DEMO_PANEL_SOURCE
|
||||
${CMAKE_SOURCE_DIR}/new_editor/src/panels/XCUIDemoPanel.cpp
|
||||
)
|
||||
set(NEW_EDITOR_BASE_PANEL_SOURCE
|
||||
${CMAKE_SOURCE_DIR}/new_editor/src/panels/Panel.cpp
|
||||
)
|
||||
@@ -237,6 +243,10 @@ if(EXISTS "${NEW_EDITOR_LAYOUT_LAB_PANEL_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_LAYOUT_LAB_RUNTIME_SOURCE}" AND
|
||||
EXISTS "${NEW_EDITOR_ASSET_DOCUMENT_SOURCE_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_ASSET_DOCUMENT_SOURCE}" AND
|
||||
EXISTS "${NEW_EDITOR_INPUT_BRIDGE_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_INPUT_BRIDGE_SOURCE}" AND
|
||||
EXISTS "${NEW_EDITOR_IMGUI_INPUT_ADAPTER_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_IMGUI_INPUT_ADAPTER_SOURCE}" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test_xcui_layout_lab_panel.cpp" AND
|
||||
EXISTS "${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp")
|
||||
add_executable(new_editor_xcui_layout_lab_panel_tests
|
||||
@@ -245,6 +255,8 @@ if(EXISTS "${NEW_EDITOR_LAYOUT_LAB_PANEL_HEADER}" AND
|
||||
${NEW_EDITOR_BASE_PANEL_SOURCE}
|
||||
${NEW_EDITOR_LAYOUT_LAB_RUNTIME_SOURCE}
|
||||
${NEW_EDITOR_ASSET_DOCUMENT_SOURCE}
|
||||
${NEW_EDITOR_INPUT_BRIDGE_SOURCE}
|
||||
${NEW_EDITOR_IMGUI_INPUT_ADAPTER_SOURCE}
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_draw.cpp
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_tables.cpp
|
||||
@@ -274,7 +286,59 @@ if(EXISTS "${NEW_EDITOR_LAYOUT_LAB_PANEL_HEADER}" AND
|
||||
|
||||
xcengine_discover_new_editor_gtests(new_editor_xcui_layout_lab_panel_tests)
|
||||
else()
|
||||
message(STATUS "Skipping new_editor_xcui_layout_lab_panel_tests because panel, runtime, test, or ImGui sources are missing.")
|
||||
message(STATUS "Skipping new_editor_xcui_layout_lab_panel_tests because panel, runtime, test, input bridge, or ImGui sources are missing.")
|
||||
endif()
|
||||
|
||||
if(EXISTS "${NEW_EDITOR_DEMO_PANEL_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_DEMO_PANEL_SOURCE}" AND
|
||||
EXISTS "${NEW_EDITOR_RUNTIME_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_RUNTIME_SOURCE}" AND
|
||||
EXISTS "${NEW_EDITOR_ASSET_DOCUMENT_SOURCE_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_ASSET_DOCUMENT_SOURCE}" AND
|
||||
EXISTS "${NEW_EDITOR_INPUT_BRIDGE_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_INPUT_BRIDGE_SOURCE}" AND
|
||||
EXISTS "${NEW_EDITOR_IMGUI_INPUT_ADAPTER_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_IMGUI_INPUT_ADAPTER_SOURCE}" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test_xcui_demo_panel.cpp" AND
|
||||
EXISTS "${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp")
|
||||
add_executable(new_editor_xcui_demo_panel_tests
|
||||
test_xcui_demo_panel.cpp
|
||||
${NEW_EDITOR_DEMO_PANEL_SOURCE}
|
||||
${NEW_EDITOR_BASE_PANEL_SOURCE}
|
||||
${NEW_EDITOR_RUNTIME_SOURCE}
|
||||
${NEW_EDITOR_ASSET_DOCUMENT_SOURCE}
|
||||
${NEW_EDITOR_INPUT_BRIDGE_SOURCE}
|
||||
${NEW_EDITOR_IMGUI_INPUT_ADAPTER_SOURCE}
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_draw.cpp
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_tables.cpp
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_widgets.cpp
|
||||
)
|
||||
|
||||
xcengine_configure_new_editor_test_target(new_editor_xcui_demo_panel_tests)
|
||||
|
||||
target_link_libraries(new_editor_xcui_demo_panel_tests
|
||||
PRIVATE
|
||||
XCEngine
|
||||
GTest::gtest
|
||||
GTest::gtest_main
|
||||
user32
|
||||
comdlg32
|
||||
)
|
||||
|
||||
target_include_directories(new_editor_xcui_demo_panel_tests PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/engine/include
|
||||
${CMAKE_SOURCE_DIR}/new_editor/src
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/backends
|
||||
)
|
||||
target_compile_definitions(new_editor_xcui_demo_panel_tests PRIVATE
|
||||
XCENGINE_NEW_EDITOR_REPO_ROOT="${XCENGINE_TEST_REPO_ROOT_CMAKE}"
|
||||
)
|
||||
|
||||
xcengine_discover_new_editor_gtests(new_editor_xcui_demo_panel_tests)
|
||||
else()
|
||||
message(STATUS "Skipping new_editor_xcui_demo_panel_tests because panel, runtime, test, input bridge, or ImGui sources are missing.")
|
||||
endif()
|
||||
|
||||
if(EXISTS "${NEW_EDITOR_BACKEND_HEADER}" AND EXISTS "${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp")
|
||||
@@ -511,11 +575,14 @@ endif()
|
||||
|
||||
if(EXISTS "${NEW_EDITOR_IMGUI_INPUT_ADAPTER_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_IMGUI_INPUT_ADAPTER_SOURCE}" AND
|
||||
EXISTS "${NEW_EDITOR_INPUT_BRIDGE_HEADER}" AND
|
||||
EXISTS "${NEW_EDITOR_INPUT_BRIDGE_SOURCE}" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test_imgui_xcui_input_adapter.cpp" AND
|
||||
EXISTS "${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp")
|
||||
add_executable(new_editor_imgui_xcui_input_adapter_tests
|
||||
test_imgui_xcui_input_adapter.cpp
|
||||
${NEW_EDITOR_IMGUI_INPUT_ADAPTER_SOURCE}
|
||||
${NEW_EDITOR_INPUT_BRIDGE_SOURCE}
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_draw.cpp
|
||||
${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_tables.cpp
|
||||
@@ -542,7 +609,7 @@ if(EXISTS "${NEW_EDITOR_IMGUI_INPUT_ADAPTER_HEADER}" AND
|
||||
|
||||
xcengine_discover_new_editor_gtests(new_editor_imgui_xcui_input_adapter_tests)
|
||||
else()
|
||||
message(STATUS "Skipping new_editor_imgui_xcui_input_adapter_tests because ImGui adapter files, test source, or ImGui sources are missing.")
|
||||
message(STATUS "Skipping new_editor_imgui_xcui_input_adapter_tests because ImGui adapter files, input bridge files, test source, or ImGui sources are missing.")
|
||||
endif()
|
||||
|
||||
if(EXISTS "${NEW_EDITOR_RHI_COMMAND_SUPPORT_HEADER}")
|
||||
|
||||
@@ -38,59 +38,77 @@ struct ShellCommandHarness {
|
||||
"new_editor.panels.xcui_layout_lab",
|
||||
true,
|
||||
true,
|
||||
Application::ShellHostedPreviewMode::LegacyImGui
|
||||
Application::ShellHostedPreviewMode::HostedPresenter
|
||||
};
|
||||
}
|
||||
|
||||
Application::ShellPanelChromeState& Panel(Application::ShellPanelId panelId) {
|
||||
return panels[ToPanelIndex(panelId)];
|
||||
}
|
||||
|
||||
const Application::ShellPanelChromeState& Panel(Application::ShellPanelId panelId) const {
|
||||
return panels[ToPanelIndex(panelId)];
|
||||
}
|
||||
|
||||
Application::ShellCommandBindings BuildBindings() {
|
||||
Application::ShellCommandBindings bindings = {};
|
||||
bindings.getXCUIDemoPanelVisible = [this]() { return Panel(Application::ShellPanelId::XCUIDemo).visible; };
|
||||
bindings.getXCUIDemoPanelVisible = [this]() {
|
||||
return Panel(Application::ShellPanelId::XCUIDemo).visible;
|
||||
};
|
||||
bindings.setXCUIDemoPanelVisible = [this](bool visible) {
|
||||
Panel(Application::ShellPanelId::XCUIDemo).visible = visible;
|
||||
panels[ToPanelIndex(Application::ShellPanelId::XCUIDemo)].visible = visible;
|
||||
};
|
||||
bindings.getXCUILayoutLabPanelVisible = [this]() {
|
||||
return Panel(Application::ShellPanelId::XCUILayoutLab).visible;
|
||||
};
|
||||
bindings.setXCUILayoutLabPanelVisible = [this](bool visible) {
|
||||
Panel(Application::ShellPanelId::XCUILayoutLab).visible = visible;
|
||||
panels[ToPanelIndex(Application::ShellPanelId::XCUILayoutLab)].visible = visible;
|
||||
};
|
||||
bindings.getImGuiDemoWindowVisible = [this]() {
|
||||
return viewToggles.imguiDemoWindowVisible;
|
||||
};
|
||||
bindings.setImGuiDemoWindowVisible = [this](bool visible) {
|
||||
viewToggles.imguiDemoWindowVisible = visible;
|
||||
};
|
||||
bindings.getNativeBackdropVisible = [this]() {
|
||||
return viewToggles.nativeBackdropVisible;
|
||||
};
|
||||
bindings.setNativeBackdropVisible = [this](bool visible) {
|
||||
viewToggles.nativeBackdropVisible = visible;
|
||||
};
|
||||
bindings.getPulseAccentEnabled = [this]() {
|
||||
return viewToggles.pulseAccentEnabled;
|
||||
};
|
||||
bindings.setPulseAccentEnabled = [this](bool enabled) {
|
||||
viewToggles.pulseAccentEnabled = enabled;
|
||||
};
|
||||
bindings.getNativeXCUIOverlayVisible = [this]() {
|
||||
return viewToggles.nativeXCUIOverlayVisible;
|
||||
};
|
||||
bindings.setNativeXCUIOverlayVisible = [this](bool visible) {
|
||||
viewToggles.nativeXCUIOverlayVisible = visible;
|
||||
};
|
||||
bindings.getHostedPreviewHudVisible = [this]() {
|
||||
return viewToggles.hostedPreviewHudVisible;
|
||||
};
|
||||
bindings.setHostedPreviewHudVisible = [this](bool visible) {
|
||||
viewToggles.hostedPreviewHudVisible = visible;
|
||||
};
|
||||
bindings.getImGuiDemoWindowVisible = [this]() { return viewToggles.imguiDemoWindowVisible; };
|
||||
bindings.setImGuiDemoWindowVisible = [this](bool visible) { viewToggles.imguiDemoWindowVisible = visible; };
|
||||
bindings.getNativeBackdropVisible = [this]() { return viewToggles.nativeBackdropVisible; };
|
||||
bindings.setNativeBackdropVisible = [this](bool visible) { viewToggles.nativeBackdropVisible = visible; };
|
||||
bindings.getPulseAccentEnabled = [this]() { return viewToggles.pulseAccentEnabled; };
|
||||
bindings.setPulseAccentEnabled = [this](bool enabled) { viewToggles.pulseAccentEnabled = enabled; };
|
||||
bindings.getNativeXCUIOverlayVisible = [this]() { return viewToggles.nativeXCUIOverlayVisible; };
|
||||
bindings.setNativeXCUIOverlayVisible = [this](bool visible) { viewToggles.nativeXCUIOverlayVisible = visible; };
|
||||
bindings.getHostedPreviewHudVisible = [this]() { return viewToggles.hostedPreviewHudVisible; };
|
||||
bindings.setHostedPreviewHudVisible = [this](bool visible) { viewToggles.hostedPreviewHudVisible = visible; };
|
||||
bindings.getNativeDemoPanelPreviewEnabled = [this]() {
|
||||
return Panel(Application::ShellPanelId::XCUIDemo).previewMode ==
|
||||
Application::ShellHostedPreviewMode::NativeOffscreen;
|
||||
};
|
||||
bindings.setNativeDemoPanelPreviewEnabled = [this](bool enabled) {
|
||||
Panel(Application::ShellPanelId::XCUIDemo).previewMode =
|
||||
panels[ToPanelIndex(Application::ShellPanelId::XCUIDemo)].previewMode =
|
||||
enabled
|
||||
? Application::ShellHostedPreviewMode::NativeOffscreen
|
||||
: Application::ShellHostedPreviewMode::LegacyImGui;
|
||||
: Application::ShellHostedPreviewMode::HostedPresenter;
|
||||
};
|
||||
bindings.getNativeLayoutLabPreviewEnabled = [this]() {
|
||||
return Panel(Application::ShellPanelId::XCUILayoutLab).previewMode ==
|
||||
Application::ShellHostedPreviewMode::NativeOffscreen;
|
||||
};
|
||||
bindings.setNativeLayoutLabPreviewEnabled = [this](bool enabled) {
|
||||
Panel(Application::ShellPanelId::XCUILayoutLab).previewMode =
|
||||
panels[ToPanelIndex(Application::ShellPanelId::XCUILayoutLab)].previewMode =
|
||||
enabled
|
||||
? Application::ShellHostedPreviewMode::NativeOffscreen
|
||||
: Application::ShellHostedPreviewMode::LegacyImGui;
|
||||
: Application::ShellHostedPreviewMode::HostedPresenter;
|
||||
};
|
||||
bindings.onHostedPreviewModeChanged = [this]() { ++hostedPreviewReconfigureCount; };
|
||||
return bindings;
|
||||
@@ -134,7 +152,7 @@ TEST(ApplicationShellCommandBindingsTest, PreviewModeCommandsTriggerHostedPrevie
|
||||
EXPECT_TRUE(router.InvokeCommand(Application::ShellCommandIds::ToggleNativeDemoPanelPreview));
|
||||
EXPECT_EQ(
|
||||
harness.Panel(Application::ShellPanelId::XCUIDemo).previewMode,
|
||||
Application::ShellHostedPreviewMode::LegacyImGui);
|
||||
Application::ShellHostedPreviewMode::HostedPresenter);
|
||||
EXPECT_EQ(harness.hostedPreviewReconfigureCount, 1);
|
||||
|
||||
EXPECT_TRUE(router.InvokeCommand(Application::ShellCommandIds::ToggleNativeLayoutLabPreview));
|
||||
@@ -243,7 +261,7 @@ TEST(ApplicationShellCommandBindingsTest, PreviewShortcutInvokesCommandHandlerAn
|
||||
EXPECT_TRUE(router.InvokeMatchingShortcut({ &previewSnapshot }));
|
||||
EXPECT_EQ(
|
||||
harness.Panel(Application::ShellPanelId::XCUIDemo).previewMode,
|
||||
Application::ShellHostedPreviewMode::LegacyImGui);
|
||||
Application::ShellHostedPreviewMode::HostedPresenter);
|
||||
EXPECT_EQ(harness.hostedPreviewReconfigureCount, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@ void PrepareImGui(float width = 1024.0f, float height = 768.0f) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2(width, height);
|
||||
io.DeltaTime = 1.0f / 60.0f;
|
||||
unsigned char* fontPixels = nullptr;
|
||||
int fontWidth = 0;
|
||||
int fontHeight = 0;
|
||||
io.Fonts->GetTexDataAsRGBA32(&fontPixels, &fontWidth, &fontHeight);
|
||||
io.Fonts->SetTexID(static_cast<ImTextureID>(1));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -36,17 +41,17 @@ TEST(ImGuiXCUIInputAdapterTest, CaptureSnapshotMapsImGuiStateIntoXCUIFrameSnapsh
|
||||
PrepareImGui(800.0f, 600.0f);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.MousePos = ImVec2(120.0f, 72.0f);
|
||||
io.MouseDown[0] = true;
|
||||
io.MouseWheel = 1.0f;
|
||||
io.WantCaptureMouse = true;
|
||||
io.WantCaptureKeyboard = true;
|
||||
io.WantTextInput = true;
|
||||
io.AddMousePosEvent(120.0f, 72.0f);
|
||||
io.AddMouseButtonEvent(0, true);
|
||||
io.AddMouseWheelEvent(0.0f, 1.0f);
|
||||
io.AddKeyEvent(ImGuiKey_LeftCtrl, true);
|
||||
io.AddKeyEvent(ImGuiKey_P, true);
|
||||
io.AddInputCharacter('p');
|
||||
|
||||
ImGui::NewFrame();
|
||||
io.KeyCtrl = true;
|
||||
io.KeysData[ImGuiKey_LeftCtrl - ImGuiKey_NamedKey_BEGIN].Down = true;
|
||||
io.KeysData[ImGuiKey_P - ImGuiKey_NamedKey_BEGIN].Down = true;
|
||||
io.InputQueueCharacters.resize(0);
|
||||
io.InputQueueCharacters.push_back(static_cast<ImWchar>('p'));
|
||||
|
||||
XCUIInputBridgeCaptureOptions options = {};
|
||||
options.pointerOffset = XCEngine::UI::UIPoint(20.0f, 12.0f);
|
||||
@@ -55,8 +60,6 @@ TEST(ImGuiXCUIInputAdapterTest, CaptureSnapshotMapsImGuiStateIntoXCUIFrameSnapsh
|
||||
|
||||
const auto snapshot = ImGuiXCUIInputAdapter::CaptureSnapshot(io, options);
|
||||
|
||||
ImGui::EndFrame();
|
||||
|
||||
EXPECT_FLOAT_EQ(snapshot.pointerPosition.x, 100.0f);
|
||||
EXPECT_FLOAT_EQ(snapshot.pointerPosition.y, 60.0f);
|
||||
EXPECT_TRUE(snapshot.pointerInside);
|
||||
|
||||
213
tests/NewEditor/test_xcui_demo_panel.cpp
Normal file
213
tests/NewEditor/test_xcui_demo_panel.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "panels/XCUIDemoPanel.h"
|
||||
|
||||
#include "XCUIBackend/XCUIHostedPreviewPresenter.h"
|
||||
#include "XCUIBackend/XCUIPanelCanvasHost.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace {
|
||||
|
||||
using XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter;
|
||||
using XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIHostedPreviewFrame;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIHostedPreviewStats;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIPanelCanvasRequest;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIPanelCanvasSession;
|
||||
using XCEngine::NewEditor::XCUIDemoPanel;
|
||||
|
||||
class ImGuiContextScope {
|
||||
public:
|
||||
ImGuiContextScope() {
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGui::StyleColorsDark();
|
||||
}
|
||||
|
||||
~ImGuiContextScope() {
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
};
|
||||
|
||||
void PrepareImGui(float width = 1280.0f, float height = 900.0f) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2(width, height);
|
||||
io.DeltaTime = 1.0f / 60.0f;
|
||||
unsigned char* fontPixels = nullptr;
|
||||
int fontWidth = 0;
|
||||
int fontHeight = 0;
|
||||
io.Fonts->GetTexDataAsRGBA32(&fontPixels, &fontWidth, &fontHeight);
|
||||
io.Fonts->SetTexID(static_cast<ImTextureID>(1));
|
||||
}
|
||||
|
||||
class RecordingHostedPreviewPresenter final : public IXCUIHostedPreviewPresenter {
|
||||
public:
|
||||
bool Present(const XCUIHostedPreviewFrame& frame) override {
|
||||
++presentCallCount;
|
||||
lastCanvasRect = frame.canvasRect;
|
||||
lastLogicalSize = frame.logicalSize;
|
||||
lastDebugName = frame.debugName != nullptr ? frame.debugName : "";
|
||||
|
||||
m_lastStats = {};
|
||||
if (frame.drawData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lastDrawListCount = frame.drawData->GetDrawListCount();
|
||||
lastCommandCount = frame.drawData->GetTotalCommandCount();
|
||||
m_lastStats.presented = true;
|
||||
m_lastStats.submittedDrawListCount = lastDrawListCount;
|
||||
m_lastStats.submittedCommandCount = lastCommandCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
const XCUIHostedPreviewStats& GetLastStats() const override {
|
||||
return m_lastStats;
|
||||
}
|
||||
|
||||
std::size_t presentCallCount = 0u;
|
||||
XCEngine::UI::UIRect lastCanvasRect = {};
|
||||
XCEngine::UI::UISize lastLogicalSize = {};
|
||||
std::size_t lastDrawListCount = 0u;
|
||||
std::size_t lastCommandCount = 0u;
|
||||
std::string lastDebugName = {};
|
||||
|
||||
private:
|
||||
XCUIHostedPreviewStats m_lastStats = {};
|
||||
};
|
||||
|
||||
class StubCanvasHost final : public IXCUIPanelCanvasHost {
|
||||
public:
|
||||
const char* GetDebugName() const override {
|
||||
return "StubCanvasHost";
|
||||
}
|
||||
|
||||
XCEngine::Editor::XCUIBackend::XCUIPanelCanvasHostBackend GetBackend() const override {
|
||||
return XCEngine::Editor::XCUIBackend::XCUIPanelCanvasHostBackend::Null;
|
||||
}
|
||||
|
||||
XCEngine::Editor::XCUIBackend::XCUIPanelCanvasHostCapabilities GetCapabilities() const override {
|
||||
return {};
|
||||
}
|
||||
|
||||
XCUIPanelCanvasSession BeginCanvas(const XCUIPanelCanvasRequest& request) override {
|
||||
lastRequest = request;
|
||||
++beginCanvasCallCount;
|
||||
return session;
|
||||
}
|
||||
|
||||
void DrawFilledRect(
|
||||
const XCEngine::UI::UIRect&,
|
||||
const XCEngine::UI::UIColor&,
|
||||
float) override {
|
||||
}
|
||||
|
||||
void DrawOutlineRect(
|
||||
const XCEngine::UI::UIRect&,
|
||||
const XCEngine::UI::UIColor&,
|
||||
float,
|
||||
float) override {
|
||||
}
|
||||
|
||||
void DrawText(
|
||||
const XCEngine::UI::UIPoint&,
|
||||
std::string_view,
|
||||
const XCEngine::UI::UIColor&,
|
||||
float) override {
|
||||
}
|
||||
|
||||
void EndCanvas() override {
|
||||
++endCanvasCallCount;
|
||||
}
|
||||
|
||||
std::size_t beginCanvasCallCount = 0u;
|
||||
std::size_t endCanvasCallCount = 0u;
|
||||
XCUIPanelCanvasRequest lastRequest = {};
|
||||
XCUIPanelCanvasSession session = {
|
||||
XCEngine::UI::UIRect(0.0f, 0.0f, 960.0f, 640.0f),
|
||||
XCEngine::UI::UIRect(12.0f, 18.0f, 936.0f, 512.0f),
|
||||
XCEngine::UI::UIPoint(120.0f, 140.0f),
|
||||
true,
|
||||
true,
|
||||
true
|
||||
};
|
||||
};
|
||||
|
||||
void RenderPanelFrame(XCUIDemoPanel& panel, ImGuiContextScope&) {
|
||||
PrepareImGui();
|
||||
ImGui::NewFrame();
|
||||
panel.Render();
|
||||
ImGui::Render();
|
||||
}
|
||||
|
||||
TEST(NewEditorXCUIDemoPanelTest, DefaultConstructionDoesNotAutoCreateHostedPreviewPresenter) {
|
||||
ImGuiContextScope contextScope;
|
||||
|
||||
auto canvasHost = std::make_unique<StubCanvasHost>();
|
||||
XCUIDemoPanel panel;
|
||||
panel.SetCanvasHost(std::move(canvasHost));
|
||||
|
||||
RenderPanelFrame(panel, contextScope);
|
||||
|
||||
const XCUIHostedPreviewStats& stats = panel.GetLastPreviewStats();
|
||||
EXPECT_FALSE(stats.presented);
|
||||
EXPECT_FALSE(stats.queuedToNativePass);
|
||||
EXPECT_EQ(stats.submittedDrawListCount, 0u);
|
||||
EXPECT_EQ(stats.submittedCommandCount, 0u);
|
||||
EXPECT_EQ(stats.flushedDrawListCount, 0u);
|
||||
EXPECT_EQ(stats.flushedCommandCount, 0u);
|
||||
}
|
||||
|
||||
TEST(NewEditorXCUIDemoPanelTest, ConstructorUsesGenericNullCanvasHostUntilOuterLayerInjectsOne) {
|
||||
ImGuiContextScope contextScope;
|
||||
|
||||
auto previewPresenter = std::make_unique<RecordingHostedPreviewPresenter>();
|
||||
RecordingHostedPreviewPresenter* previewPresenterPtr = previewPresenter.get();
|
||||
|
||||
XCUIDemoPanel panel(nullptr, std::move(previewPresenter));
|
||||
RenderPanelFrame(panel, contextScope);
|
||||
|
||||
ASSERT_EQ(previewPresenterPtr->presentCallCount, 1u);
|
||||
EXPECT_EQ(previewPresenterPtr->lastDebugName, "XCUI Demo");
|
||||
EXPECT_FLOAT_EQ(previewPresenterPtr->lastCanvasRect.x, 0.0f);
|
||||
EXPECT_GT(previewPresenterPtr->lastCanvasRect.y, 0.0f);
|
||||
EXPECT_FLOAT_EQ(previewPresenterPtr->lastCanvasRect.width, 0.0f);
|
||||
EXPECT_GT(previewPresenterPtr->lastCanvasRect.height, 0.0f);
|
||||
EXPECT_FLOAT_EQ(previewPresenterPtr->lastLogicalSize.width, 0.0f);
|
||||
EXPECT_FLOAT_EQ(
|
||||
previewPresenterPtr->lastLogicalSize.height,
|
||||
previewPresenterPtr->lastCanvasRect.height);
|
||||
}
|
||||
|
||||
TEST(NewEditorXCUIDemoPanelTest, ClearingHostedPreviewPresenterDoesNotRestoreImGuiFallback) {
|
||||
ImGuiContextScope contextScope;
|
||||
|
||||
auto previewPresenter = std::make_unique<RecordingHostedPreviewPresenter>();
|
||||
RecordingHostedPreviewPresenter* previewPresenterPtr = previewPresenter.get();
|
||||
auto canvasHost = std::make_unique<StubCanvasHost>();
|
||||
|
||||
XCUIDemoPanel panel(nullptr, std::move(previewPresenter));
|
||||
panel.SetCanvasHost(std::move(canvasHost));
|
||||
|
||||
RenderPanelFrame(panel, contextScope);
|
||||
ASSERT_EQ(previewPresenterPtr->presentCallCount, 1u);
|
||||
EXPECT_TRUE(panel.GetLastPreviewStats().presented);
|
||||
|
||||
panel.SetHostedPreviewPresenter(nullptr);
|
||||
RenderPanelFrame(panel, contextScope);
|
||||
|
||||
const XCUIHostedPreviewStats& stats = panel.GetLastPreviewStats();
|
||||
EXPECT_FALSE(stats.presented);
|
||||
EXPECT_FALSE(stats.queuedToNativePass);
|
||||
EXPECT_EQ(stats.submittedDrawListCount, 0u);
|
||||
EXPECT_EQ(stats.submittedCommandCount, 0u);
|
||||
EXPECT_EQ(stats.flushedDrawListCount, 0u);
|
||||
EXPECT_EQ(stats.flushedCommandCount, 0u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace {
|
||||
|
||||
using XCEngine::Editor::XCUIBackend::CreateImGuiXCUIHostedPreviewPresenter;
|
||||
using XCEngine::Editor::XCUIBackend::CreateNullXCUIHostedPreviewPresenter;
|
||||
using XCEngine::Editor::XCUIBackend::CreateQueuedNativeXCUIHostedPreviewPresenter;
|
||||
using XCEngine::Editor::XCUIBackend::IImGuiXCUIHostedPreviewTargetBinding;
|
||||
using XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter;
|
||||
@@ -92,6 +93,80 @@ TEST(XCUIHostedPreviewPresenterTest, PresentReturnsFalseAndClearsStatsWhenFrameH
|
||||
EXPECT_EQ(stats.flushedCommandCount, 0u);
|
||||
}
|
||||
|
||||
TEST(XCUIHostedPreviewPresenterTest, NullPresenterReturnsFalseAndClearsStatsWhenFrameHasNoDrawData) {
|
||||
std::unique_ptr<IXCUIHostedPreviewPresenter> presenter = CreateNullXCUIHostedPreviewPresenter();
|
||||
ASSERT_NE(presenter, nullptr);
|
||||
|
||||
XCUIHostedPreviewFrame frame = {};
|
||||
const bool presented = presenter->Present(frame);
|
||||
const XCUIHostedPreviewStats& stats = presenter->GetLastStats();
|
||||
|
||||
EXPECT_FALSE(presented);
|
||||
EXPECT_FALSE(stats.presented);
|
||||
EXPECT_FALSE(stats.queuedToNativePass);
|
||||
EXPECT_EQ(stats.submittedDrawListCount, 0u);
|
||||
EXPECT_EQ(stats.submittedCommandCount, 0u);
|
||||
EXPECT_EQ(stats.flushedDrawListCount, 0u);
|
||||
EXPECT_EQ(stats.flushedCommandCount, 0u);
|
||||
}
|
||||
|
||||
TEST(XCUIHostedPreviewPresenterTest, NullPresenterAcceptsDrawDataWithoutPresentingOrQueueing) {
|
||||
std::unique_ptr<IXCUIHostedPreviewPresenter> presenter = CreateNullXCUIHostedPreviewPresenter();
|
||||
ASSERT_NE(presenter, nullptr);
|
||||
|
||||
XCEngine::UI::UIDrawData drawData = {};
|
||||
XCEngine::UI::UIDrawList& drawList = drawData.EmplaceDrawList("HostedPreviewNull");
|
||||
drawList.AddFilledRect(
|
||||
XCEngine::UI::UIRect(12.0f, 14.0f, 48.0f, 30.0f),
|
||||
XCEngine::UI::UIColor(0.25f, 0.5f, 0.8f, 1.0f));
|
||||
drawList.AddText(
|
||||
XCEngine::UI::UIPoint(18.0f, 24.0f),
|
||||
"null",
|
||||
XCEngine::UI::UIColor(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
14.0f);
|
||||
|
||||
XCUIHostedPreviewFrame frame = {};
|
||||
frame.drawData = &drawData;
|
||||
frame.debugName = "XCUI Null Preview";
|
||||
|
||||
const bool presented = presenter->Present(frame);
|
||||
const XCUIHostedPreviewStats& stats = presenter->GetLastStats();
|
||||
|
||||
EXPECT_FALSE(presented);
|
||||
EXPECT_FALSE(stats.presented);
|
||||
EXPECT_FALSE(stats.queuedToNativePass);
|
||||
EXPECT_EQ(stats.submittedDrawListCount, 1u);
|
||||
EXPECT_EQ(stats.submittedCommandCount, 2u);
|
||||
EXPECT_EQ(stats.flushedDrawListCount, 0u);
|
||||
EXPECT_EQ(stats.flushedCommandCount, 0u);
|
||||
}
|
||||
|
||||
TEST(XCUIHostedPreviewPresenterTest, NullPresenterSurfaceQueriesReturnFalseAndClearOutputs) {
|
||||
std::unique_ptr<IXCUIHostedPreviewPresenter> presenter = CreateNullXCUIHostedPreviewPresenter();
|
||||
ASSERT_NE(presenter, nullptr);
|
||||
|
||||
XCUIHostedPreviewSurfaceDescriptor descriptor = {};
|
||||
descriptor.debugName = "stale";
|
||||
descriptor.debugSource = "stale";
|
||||
descriptor.queuedThisFrame = true;
|
||||
|
||||
XCUIHostedPreviewSurfaceImage image = {};
|
||||
image.texture = MakeHostedPreviewTextureHandle(29u, 256u, 128u);
|
||||
image.surfaceWidth = 256u;
|
||||
image.surfaceHeight = 128u;
|
||||
|
||||
EXPECT_FALSE(presenter->TryGetSurfaceDescriptor("XCUI Demo", descriptor));
|
||||
EXPECT_TRUE(descriptor.debugName.empty());
|
||||
EXPECT_TRUE(descriptor.debugSource.empty());
|
||||
EXPECT_FALSE(descriptor.queuedThisFrame);
|
||||
EXPECT_FALSE(descriptor.image.IsValid());
|
||||
|
||||
EXPECT_FALSE(presenter->TryGetSurfaceImage("XCUI Demo", image));
|
||||
EXPECT_FALSE(image.IsValid());
|
||||
EXPECT_EQ(image.surfaceWidth, 0u);
|
||||
EXPECT_EQ(image.surfaceHeight, 0u);
|
||||
}
|
||||
|
||||
TEST(XCUIHostedPreviewPresenterTest, PresentFlushesDrawDataIntoExplicitBindingResolvedImGuiDrawList) {
|
||||
ImGuiContextScope contextScope;
|
||||
PrepareImGui(800.0f, 600.0f);
|
||||
@@ -229,7 +304,7 @@ TEST(XCUIHostedPreviewPresenterTest, PresentFlushesDrawDataIntoExplicitBindingRe
|
||||
EXPECT_GE(targetDrawList->CmdBuffer.Size, baselineCommandCount);
|
||||
}
|
||||
|
||||
TEST(XCUIHostedPreviewPresenterTest, DefaultFactoryStillUsesCurrentWindowBindingForLegacyImGuiPath) {
|
||||
TEST(XCUIHostedPreviewPresenterTest, DefaultFactoryStillUsesCurrentWindowBindingForImGuiPresenterPath) {
|
||||
ImGuiContextScope contextScope;
|
||||
PrepareImGui(800.0f, 600.0f);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "panels/XCUILayoutLabPanel.h"
|
||||
|
||||
#include "XCUIBackend/ImGuiXCUIInputSource.h"
|
||||
#include "XCUIBackend/XCUIHostedPreviewPresenter.h"
|
||||
#include "XCUIBackend/XCUIPanelCanvasHost.h"
|
||||
|
||||
@@ -15,6 +16,7 @@ namespace {
|
||||
|
||||
using XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter;
|
||||
using XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost;
|
||||
using XCEngine::Editor::XCUIBackend::ImGuiXCUIInputSnapshotSource;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIHostedPreviewFrame;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIHostedPreviewStats;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIPanelCanvasRequest;
|
||||
@@ -155,13 +157,15 @@ void ClickElement(
|
||||
RenderPanelFrame(
|
||||
panel,
|
||||
contextScope,
|
||||
[](ImGuiIO& io) {
|
||||
[clickPoint](ImGuiIO& io) {
|
||||
io.AddMousePosEvent(clickPoint.x, clickPoint.y);
|
||||
io.AddMouseButtonEvent(ImGuiMouseButton_Left, true);
|
||||
});
|
||||
RenderPanelFrame(
|
||||
panel,
|
||||
contextScope,
|
||||
[](ImGuiIO& io) {
|
||||
[clickPoint](ImGuiIO& io) {
|
||||
io.AddMousePosEvent(clickPoint.x, clickPoint.y);
|
||||
io.AddMouseButtonEvent(ImGuiMouseButton_Left, false);
|
||||
});
|
||||
}
|
||||
@@ -190,10 +194,10 @@ TEST(NewEditorXCUILayoutLabPanelTest, MapsPreviousNextHomeAndEndIntoRuntimeNavig
|
||||
auto previewPresenter = std::make_unique<StubHostedPreviewPresenter>();
|
||||
auto canvasHost = std::make_unique<StubCanvasHost>();
|
||||
StubCanvasHost* canvasHostPtr = canvasHost.get();
|
||||
ImGuiXCUIInputSnapshotSource inputSource(nullptr);
|
||||
|
||||
XCUILayoutLabPanel panel(nullptr, std::move(previewPresenter));
|
||||
XCUILayoutLabPanel panel(&inputSource, std::move(previewPresenter), std::move(canvasHost));
|
||||
panel.SetHostedPreviewEnabled(false);
|
||||
panel.SetCanvasHost(std::move(canvasHost));
|
||||
|
||||
RenderPanelFrame(panel, contextScope);
|
||||
ClickElement(panel, *canvasHostPtr, "assetLighting", contextScope);
|
||||
@@ -223,10 +227,10 @@ TEST(NewEditorXCUILayoutLabPanelTest, MapsCollapseAndExpandIntoRuntimeNavigation
|
||||
auto previewPresenter = std::make_unique<StubHostedPreviewPresenter>();
|
||||
auto canvasHost = std::make_unique<StubCanvasHost>();
|
||||
StubCanvasHost* canvasHostPtr = canvasHost.get();
|
||||
ImGuiXCUIInputSnapshotSource inputSource(nullptr);
|
||||
|
||||
XCUILayoutLabPanel panel(nullptr, std::move(previewPresenter));
|
||||
XCUILayoutLabPanel panel(&inputSource, std::move(previewPresenter), std::move(canvasHost));
|
||||
panel.SetHostedPreviewEnabled(false);
|
||||
panel.SetCanvasHost(std::move(canvasHost));
|
||||
|
||||
RenderPanelFrame(panel, contextScope);
|
||||
ClickElement(panel, *canvasHostPtr, "treeScenes", contextScope);
|
||||
@@ -250,4 +254,17 @@ TEST(NewEditorXCUILayoutLabPanelTest, MapsCollapseAndExpandIntoRuntimeNavigation
|
||||
EXPECT_EQ(panel.GetFrameResult().stats.selectedElementId, "treeScenes");
|
||||
}
|
||||
|
||||
TEST(NewEditorXCUILayoutLabPanelTest, DefaultFallbackDoesNotCreateImplicitHostedPreviewPresenter) {
|
||||
ImGuiContextScope contextScope;
|
||||
|
||||
XCUILayoutLabPanel panel(nullptr);
|
||||
|
||||
RenderPanelFrame(panel, contextScope);
|
||||
|
||||
EXPECT_FALSE(panel.IsUsingNativeHostedPreview());
|
||||
EXPECT_FALSE(panel.GetLastPreviewStats().presented);
|
||||
EXPECT_EQ(panel.GetLastPreviewStats().submittedDrawListCount, 0u);
|
||||
EXPECT_EQ(panel.GetLastPreviewStats().submittedCommandCount, 0u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
namespace {
|
||||
|
||||
using XCEngine::Editor::XCUIBackend::CreateNullXCUIPanelCanvasHost;
|
||||
using XCEngine::Editor::XCUIBackend::BuildPassiveXCUIPanelCanvasSession;
|
||||
using XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost;
|
||||
using XCEngine::Editor::XCUIBackend::ResolveXCUIPanelCanvasChildId;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIPanelCanvasHostBackend;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIPanelCanvasHostCapabilities;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIPanelCanvasRequest;
|
||||
@@ -24,7 +26,41 @@ TEST(NewEditorXCUIPanelCanvasHostTest, NullHostReportsExplicitBackendAndCapabili
|
||||
EXPECT_FALSE(capabilities.supportsPrimitiveOverlays);
|
||||
}
|
||||
|
||||
TEST(NewEditorXCUIPanelCanvasHostTest, NullHostBeginCanvasReturnsEmptySessionAndDrawCallsAreNoops) {
|
||||
TEST(NewEditorXCUIPanelCanvasHostTest, ResolveChildIdFallsBackToStableDefaultForMissingNames) {
|
||||
XCUIPanelCanvasRequest request = {};
|
||||
EXPECT_STREQ(ResolveXCUIPanelCanvasChildId(request), "XCUIPanelCanvasHost");
|
||||
EXPECT_STREQ(ResolveXCUIPanelCanvasChildId(request, "FallbackCanvas"), "FallbackCanvas");
|
||||
|
||||
request.childId = "";
|
||||
EXPECT_STREQ(ResolveXCUIPanelCanvasChildId(request), "XCUIPanelCanvasHost");
|
||||
|
||||
request.childId = "CanvasHost";
|
||||
EXPECT_STREQ(ResolveXCUIPanelCanvasChildId(request, "FallbackCanvas"), "CanvasHost");
|
||||
}
|
||||
|
||||
TEST(NewEditorXCUIPanelCanvasHostTest, PassiveSessionClampsRequestGeometryIntoSafeDefaultState) {
|
||||
XCUIPanelCanvasRequest request = {};
|
||||
request.height = -18.0f;
|
||||
request.topInset = 42.0f;
|
||||
|
||||
XCUIPanelCanvasSession session = BuildPassiveXCUIPanelCanvasSession(request);
|
||||
EXPECT_FALSE(session.validCanvas);
|
||||
EXPECT_FALSE(session.hovered);
|
||||
EXPECT_FALSE(session.windowFocused);
|
||||
EXPECT_FLOAT_EQ(session.hostRect.width, 0.0f);
|
||||
EXPECT_FLOAT_EQ(session.hostRect.height, 0.0f);
|
||||
EXPECT_FLOAT_EQ(session.canvasRect.y, 0.0f);
|
||||
EXPECT_FLOAT_EQ(session.canvasRect.height, 0.0f);
|
||||
|
||||
request.height = 120.0f;
|
||||
request.topInset = 180.0f;
|
||||
session = BuildPassiveXCUIPanelCanvasSession(request);
|
||||
EXPECT_FLOAT_EQ(session.hostRect.height, 120.0f);
|
||||
EXPECT_FLOAT_EQ(session.canvasRect.y, 120.0f);
|
||||
EXPECT_FLOAT_EQ(session.canvasRect.height, 0.0f);
|
||||
}
|
||||
|
||||
TEST(NewEditorXCUIPanelCanvasHostTest, NullHostBeginCanvasReturnsSafePassiveSessionAndDrawCallsAreNoops) {
|
||||
std::unique_ptr<IXCUIPanelCanvasHost> host = CreateNullXCUIPanelCanvasHost();
|
||||
ASSERT_NE(host, nullptr);
|
||||
|
||||
@@ -43,9 +79,12 @@ TEST(NewEditorXCUIPanelCanvasHostTest, NullHostBeginCanvasReturnsEmptySessionAnd
|
||||
EXPECT_FALSE(session.hovered);
|
||||
EXPECT_FALSE(session.windowFocused);
|
||||
EXPECT_FLOAT_EQ(session.hostRect.width, 0.0f);
|
||||
EXPECT_FLOAT_EQ(session.hostRect.height, 0.0f);
|
||||
EXPECT_FLOAT_EQ(session.hostRect.height, 280.0f);
|
||||
EXPECT_FLOAT_EQ(session.canvasRect.width, 0.0f);
|
||||
EXPECT_FLOAT_EQ(session.canvasRect.height, 0.0f);
|
||||
EXPECT_FLOAT_EQ(session.canvasRect.y, 24.0f);
|
||||
EXPECT_FLOAT_EQ(session.canvasRect.height, 256.0f);
|
||||
EXPECT_FLOAT_EQ(session.pointerPosition.x, 0.0f);
|
||||
EXPECT_FLOAT_EQ(session.pointerPosition.y, 0.0f);
|
||||
|
||||
host->DrawFilledRect(
|
||||
XCEngine::UI::UIRect(10.0f, 12.0f, 48.0f, 64.0f),
|
||||
@@ -62,6 +101,11 @@ TEST(NewEditorXCUIPanelCanvasHostTest, NullHostBeginCanvasReturnsEmptySessionAnd
|
||||
XCEngine::UI::UIColor(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
16.0f);
|
||||
host->EndCanvas();
|
||||
|
||||
const XCUIPanelCanvasSession secondSession = host->BeginCanvas({});
|
||||
EXPECT_FLOAT_EQ(secondSession.hostRect.height, 0.0f);
|
||||
EXPECT_FLOAT_EQ(secondSession.canvasRect.height, 0.0f);
|
||||
host->EndCanvas();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
namespace {
|
||||
|
||||
using XCEngine::Editor::XCUIBackend::XCUIShellChromeCommandIds;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIShellCommandDescriptor;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIShellChromeState;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIShellHostedPreviewMode;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIShellHostedPreviewState;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIShellMenuItemKind;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIShellPanelId;
|
||||
using XCEngine::Editor::XCUIBackend::XCUIShellViewToggleId;
|
||||
|
||||
@@ -33,7 +35,7 @@ TEST(XCUIShellChromeStateTest, DefaultsMatchCurrentShellChromeConfiguration) {
|
||||
state.GetHostedPreviewState(XCUIShellPanelId::XCUIDemo),
|
||||
XCUIShellHostedPreviewState::NativeOffscreen);
|
||||
EXPECT_TRUE(state.IsNativeHostedPreviewActive(XCUIShellPanelId::XCUIDemo));
|
||||
EXPECT_FALSE(state.IsLegacyHostedPreviewActive(XCUIShellPanelId::XCUIDemo));
|
||||
EXPECT_FALSE(state.IsHostedPresenterPreviewActive(XCUIShellPanelId::XCUIDemo));
|
||||
|
||||
const auto* layoutLabPanel = state.TryGetPanelState(XCUIShellPanelId::XCUILayoutLab);
|
||||
ASSERT_NE(layoutLabPanel, nullptr);
|
||||
@@ -42,12 +44,12 @@ TEST(XCUIShellChromeStateTest, DefaultsMatchCurrentShellChromeConfiguration) {
|
||||
EXPECT_EQ(layoutLabPanel->previewDebugSource, "new_editor.panels.xcui_layout_lab");
|
||||
EXPECT_TRUE(layoutLabPanel->visible);
|
||||
EXPECT_TRUE(layoutLabPanel->hostedPreviewEnabled);
|
||||
EXPECT_EQ(layoutLabPanel->previewMode, XCUIShellHostedPreviewMode::LegacyImGui);
|
||||
EXPECT_EQ(layoutLabPanel->previewMode, XCUIShellHostedPreviewMode::HostedPresenter);
|
||||
EXPECT_EQ(
|
||||
state.GetHostedPreviewState(XCUIShellPanelId::XCUILayoutLab),
|
||||
XCUIShellHostedPreviewState::LegacyImGui);
|
||||
XCUIShellHostedPreviewState::HostedPresenter);
|
||||
EXPECT_FALSE(state.IsNativeHostedPreviewActive(XCUIShellPanelId::XCUILayoutLab));
|
||||
EXPECT_TRUE(state.IsLegacyHostedPreviewActive(XCUIShellPanelId::XCUILayoutLab));
|
||||
EXPECT_TRUE(state.IsHostedPresenterPreviewActive(XCUIShellPanelId::XCUILayoutLab));
|
||||
}
|
||||
|
||||
TEST(XCUIShellChromeStateTest, PanelVisibilityAndPreviewModeMutatorsTrackStateChanges) {
|
||||
@@ -64,7 +66,7 @@ TEST(XCUIShellChromeStateTest, PanelVisibilityAndPreviewModeMutatorsTrackStateCh
|
||||
EXPECT_FALSE(state.SetHostedPreviewEnabled(XCUIShellPanelId::XCUILayoutLab, false));
|
||||
EXPECT_EQ(
|
||||
state.GetHostedPreviewMode(XCUIShellPanelId::XCUILayoutLab),
|
||||
XCUIShellHostedPreviewMode::LegacyImGui);
|
||||
XCUIShellHostedPreviewMode::HostedPresenter);
|
||||
|
||||
EXPECT_TRUE(state.ToggleHostedPreviewMode(XCUIShellPanelId::XCUILayoutLab));
|
||||
EXPECT_EQ(
|
||||
@@ -72,13 +74,13 @@ TEST(XCUIShellChromeStateTest, PanelVisibilityAndPreviewModeMutatorsTrackStateCh
|
||||
XCUIShellHostedPreviewMode::NativeOffscreen);
|
||||
EXPECT_TRUE(state.SetHostedPreviewMode(
|
||||
XCUIShellPanelId::XCUILayoutLab,
|
||||
XCUIShellHostedPreviewMode::LegacyImGui));
|
||||
XCUIShellHostedPreviewMode::HostedPresenter));
|
||||
EXPECT_EQ(
|
||||
state.GetHostedPreviewMode(XCUIShellPanelId::XCUILayoutLab),
|
||||
XCUIShellHostedPreviewMode::LegacyImGui);
|
||||
XCUIShellHostedPreviewMode::HostedPresenter);
|
||||
EXPECT_FALSE(state.SetHostedPreviewMode(
|
||||
XCUIShellPanelId::XCUILayoutLab,
|
||||
XCUIShellHostedPreviewMode::LegacyImGui));
|
||||
XCUIShellHostedPreviewMode::HostedPresenter));
|
||||
}
|
||||
|
||||
TEST(XCUIShellChromeStateTest, HostedPreviewStateSeparatesEnablementFromRequestedMode) {
|
||||
@@ -93,14 +95,14 @@ TEST(XCUIShellChromeStateTest, HostedPreviewStateSeparatesEnablementFromRequeste
|
||||
state.GetHostedPreviewState(XCUIShellPanelId::XCUIDemo),
|
||||
XCUIShellHostedPreviewState::Disabled);
|
||||
EXPECT_FALSE(state.IsNativeHostedPreviewActive(XCUIShellPanelId::XCUIDemo));
|
||||
EXPECT_FALSE(state.IsLegacyHostedPreviewActive(XCUIShellPanelId::XCUIDemo));
|
||||
EXPECT_FALSE(state.IsHostedPresenterPreviewActive(XCUIShellPanelId::XCUIDemo));
|
||||
|
||||
EXPECT_TRUE(state.SetHostedPreviewMode(
|
||||
XCUIShellPanelId::XCUIDemo,
|
||||
XCUIShellHostedPreviewMode::LegacyImGui));
|
||||
XCUIShellHostedPreviewMode::HostedPresenter));
|
||||
EXPECT_EQ(
|
||||
state.GetHostedPreviewMode(XCUIShellPanelId::XCUIDemo),
|
||||
XCUIShellHostedPreviewMode::LegacyImGui);
|
||||
XCUIShellHostedPreviewMode::HostedPresenter);
|
||||
EXPECT_EQ(
|
||||
state.GetHostedPreviewState(XCUIShellPanelId::XCUIDemo),
|
||||
XCUIShellHostedPreviewState::Disabled);
|
||||
@@ -108,9 +110,9 @@ TEST(XCUIShellChromeStateTest, HostedPreviewStateSeparatesEnablementFromRequeste
|
||||
EXPECT_TRUE(state.SetHostedPreviewEnabled(XCUIShellPanelId::XCUIDemo, true));
|
||||
EXPECT_EQ(
|
||||
state.GetHostedPreviewState(XCUIShellPanelId::XCUIDemo),
|
||||
XCUIShellHostedPreviewState::LegacyImGui);
|
||||
XCUIShellHostedPreviewState::HostedPresenter);
|
||||
EXPECT_FALSE(state.IsNativeHostedPreviewActive(XCUIShellPanelId::XCUIDemo));
|
||||
EXPECT_TRUE(state.IsLegacyHostedPreviewActive(XCUIShellPanelId::XCUIDemo));
|
||||
EXPECT_TRUE(state.IsHostedPresenterPreviewActive(XCUIShellPanelId::XCUIDemo));
|
||||
}
|
||||
|
||||
TEST(XCUIShellChromeStateTest, ViewToggleMutatorsOnlyFlipRequestedFlags) {
|
||||
@@ -148,11 +150,115 @@ TEST(XCUIShellChromeStateTest, CommandInterfaceTogglesShellViewAndPreviewStates)
|
||||
EXPECT_TRUE(state.InvokeCommand(XCUIShellChromeCommandIds::ToggleNativeLayoutLabPreview));
|
||||
EXPECT_EQ(
|
||||
state.GetHostedPreviewMode(XCUIShellPanelId::XCUILayoutLab),
|
||||
XCUIShellHostedPreviewMode::LegacyImGui);
|
||||
XCUIShellHostedPreviewMode::HostedPresenter);
|
||||
|
||||
EXPECT_FALSE(state.InvokeCommand("new_editor.view.unknown"));
|
||||
}
|
||||
|
||||
TEST(XCUIShellChromeStateTest, CommandDescriptorsMatchCurrentShellMenuLabelsShortcutsAndCheckedState) {
|
||||
XCUIShellChromeState state = {};
|
||||
XCUIShellCommandDescriptor descriptor = {};
|
||||
|
||||
ASSERT_TRUE(state.TryGetCommandDescriptor(XCUIShellChromeCommandIds::ToggleXCUIDemoPanel, descriptor));
|
||||
EXPECT_EQ(descriptor.label, "XCUI Demo");
|
||||
EXPECT_EQ(descriptor.shortcut, "Ctrl+1");
|
||||
EXPECT_EQ(descriptor.commandId, XCUIShellChromeCommandIds::ToggleXCUIDemoPanel);
|
||||
EXPECT_TRUE(descriptor.checkable);
|
||||
EXPECT_TRUE(descriptor.checked);
|
||||
EXPECT_TRUE(descriptor.enabled);
|
||||
|
||||
ASSERT_TRUE(state.TryGetCommandDescriptor(XCUIShellChromeCommandIds::ToggleHostedPreviewHud, descriptor));
|
||||
EXPECT_EQ(descriptor.label, "Hosted Preview HUD");
|
||||
EXPECT_EQ(descriptor.shortcut, "Ctrl+Shift+H");
|
||||
EXPECT_TRUE(descriptor.checked);
|
||||
|
||||
ASSERT_TRUE(state.TryGetCommandDescriptor(XCUIShellChromeCommandIds::ToggleNativeLayoutLabPreview, descriptor));
|
||||
EXPECT_EQ(descriptor.label, "Native Layout Lab Preview");
|
||||
EXPECT_EQ(descriptor.shortcut, "Ctrl+Alt+2");
|
||||
EXPECT_FALSE(descriptor.checked);
|
||||
|
||||
EXPECT_FALSE(state.TryGetCommandDescriptor("new_editor.view.unknown", descriptor));
|
||||
EXPECT_TRUE(descriptor.label.empty());
|
||||
EXPECT_TRUE(descriptor.shortcut.empty());
|
||||
EXPECT_TRUE(descriptor.commandId.empty());
|
||||
EXPECT_FALSE(descriptor.checked);
|
||||
EXPECT_FALSE(descriptor.enabled);
|
||||
}
|
||||
|
||||
TEST(XCUIShellChromeStateTest, ViewMenuDescriptorMatchesCurrentApplicationOrderingAndSeparators) {
|
||||
XCUIShellChromeState state = {};
|
||||
|
||||
const auto menu = state.BuildViewMenuDescriptor();
|
||||
ASSERT_EQ(menu.label, "View");
|
||||
ASSERT_EQ(menu.items.size(), 10u);
|
||||
|
||||
ASSERT_EQ(menu.items[0].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[0].command.label, "XCUI Demo");
|
||||
EXPECT_EQ(menu.items[0].command.shortcut, "Ctrl+1");
|
||||
EXPECT_EQ(menu.items[0].command.commandId, XCUIShellChromeCommandIds::ToggleXCUIDemoPanel);
|
||||
EXPECT_TRUE(menu.items[0].command.checked);
|
||||
|
||||
ASSERT_EQ(menu.items[1].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[1].command.label, "XCUI Layout Lab");
|
||||
EXPECT_EQ(menu.items[1].command.shortcut, "Ctrl+2");
|
||||
EXPECT_EQ(menu.items[1].command.commandId, XCUIShellChromeCommandIds::ToggleXCUILayoutLabPanel);
|
||||
|
||||
ASSERT_EQ(menu.items[2].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[2].command.label, "ImGui Demo");
|
||||
EXPECT_EQ(menu.items[2].command.shortcut, "Ctrl+3");
|
||||
EXPECT_EQ(menu.items[2].command.commandId, XCUIShellChromeCommandIds::ToggleImGuiDemoWindow);
|
||||
|
||||
EXPECT_EQ(menu.items[3].kind, XCUIShellMenuItemKind::Separator);
|
||||
|
||||
ASSERT_EQ(menu.items[4].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[4].command.label, "Native Backdrop");
|
||||
EXPECT_EQ(menu.items[4].command.shortcut, "Ctrl+Shift+B");
|
||||
EXPECT_EQ(menu.items[4].command.commandId, XCUIShellChromeCommandIds::ToggleNativeBackdrop);
|
||||
|
||||
ASSERT_EQ(menu.items[5].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[5].command.label, "Pulse Accent");
|
||||
EXPECT_EQ(menu.items[5].command.shortcut, "Ctrl+Shift+P");
|
||||
EXPECT_EQ(menu.items[5].command.commandId, XCUIShellChromeCommandIds::TogglePulseAccent);
|
||||
|
||||
ASSERT_EQ(menu.items[6].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[6].command.label, "Native XCUI Overlay");
|
||||
EXPECT_EQ(menu.items[6].command.shortcut, "Ctrl+Shift+O");
|
||||
EXPECT_EQ(menu.items[6].command.commandId, XCUIShellChromeCommandIds::ToggleNativeXCUIOverlay);
|
||||
|
||||
ASSERT_EQ(menu.items[7].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[7].command.label, "Hosted Preview HUD");
|
||||
EXPECT_EQ(menu.items[7].command.shortcut, "Ctrl+Shift+H");
|
||||
EXPECT_EQ(menu.items[7].command.commandId, XCUIShellChromeCommandIds::ToggleHostedPreviewHud);
|
||||
|
||||
ASSERT_EQ(menu.items[8].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[8].command.label, "Native Demo Panel Preview");
|
||||
EXPECT_EQ(menu.items[8].command.shortcut, "Ctrl+Alt+1");
|
||||
EXPECT_EQ(menu.items[8].command.commandId, XCUIShellChromeCommandIds::ToggleNativeDemoPanelPreview);
|
||||
|
||||
ASSERT_EQ(menu.items[9].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[9].command.label, "Native Layout Lab Preview");
|
||||
EXPECT_EQ(menu.items[9].command.shortcut, "Ctrl+Alt+2");
|
||||
EXPECT_EQ(menu.items[9].command.commandId, XCUIShellChromeCommandIds::ToggleNativeLayoutLabPreview);
|
||||
}
|
||||
|
||||
TEST(XCUIShellChromeStateTest, ViewMenuDescriptorCheckedStateTracksShellStateChanges) {
|
||||
XCUIShellChromeState state = {};
|
||||
|
||||
EXPECT_TRUE(state.SetPanelVisible(XCUIShellPanelId::XCUIDemo, false));
|
||||
EXPECT_TRUE(state.SetViewToggle(XCUIShellViewToggleId::HostedPreviewHud, false));
|
||||
EXPECT_TRUE(state.SetHostedPreviewMode(
|
||||
XCUIShellPanelId::XCUILayoutLab,
|
||||
XCUIShellHostedPreviewMode::NativeOffscreen));
|
||||
EXPECT_TRUE(state.SetHostedPreviewEnabled(XCUIShellPanelId::XCUIDemo, false));
|
||||
|
||||
const auto menu = state.BuildViewMenuDescriptor();
|
||||
|
||||
EXPECT_FALSE(menu.items[0].command.checked);
|
||||
EXPECT_FALSE(menu.items[7].command.checked);
|
||||
EXPECT_FALSE(menu.items[8].command.checked);
|
||||
EXPECT_TRUE(menu.items[9].command.checked);
|
||||
}
|
||||
|
||||
TEST(XCUIShellChromeStateTest, PanelCommandIdHelpersMatchCurrentShellCommands) {
|
||||
EXPECT_EQ(
|
||||
XCUIShellChromeState::GetPanelVisibilityCommandId(XCUIShellPanelId::XCUIDemo),
|
||||
@@ -200,12 +306,12 @@ TEST(XCUIShellChromeStateTest, InvalidPanelAndToggleIdsFailGracefully) {
|
||||
EXPECT_FALSE(state.SetHostedPreviewEnabled(invalidPanelId, false));
|
||||
EXPECT_EQ(
|
||||
state.GetHostedPreviewMode(invalidPanelId),
|
||||
XCUIShellHostedPreviewMode::LegacyImGui);
|
||||
XCUIShellHostedPreviewMode::HostedPresenter);
|
||||
EXPECT_EQ(
|
||||
state.GetHostedPreviewState(invalidPanelId),
|
||||
XCUIShellHostedPreviewState::Disabled);
|
||||
EXPECT_FALSE(state.IsNativeHostedPreviewActive(invalidPanelId));
|
||||
EXPECT_FALSE(state.IsLegacyHostedPreviewActive(invalidPanelId));
|
||||
EXPECT_FALSE(state.IsHostedPresenterPreviewActive(invalidPanelId));
|
||||
EXPECT_FALSE(state.SetHostedPreviewMode(invalidPanelId, XCUIShellHostedPreviewMode::NativeOffscreen));
|
||||
EXPECT_FALSE(state.ToggleHostedPreviewMode(invalidPanelId));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user