Default new_editor to native XCUI shell host
This commit is contained in:
@@ -2,13 +2,16 @@
|
||||
#include "XCUIBackend/ImGuiXCUIPanelCanvasHost.h"
|
||||
#include "XCUIBackend/ImGuiXCUIHostedPreviewPresenter.h"
|
||||
#include "XCUIBackend/ImGuiWindowUICompositor.h"
|
||||
#include "XCUIBackend/NativeWindowUICompositor.h"
|
||||
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace NewEditor {
|
||||
@@ -18,6 +21,14 @@ constexpr wchar_t kWindowClassName[] = L"XCNewEditorWindowClass";
|
||||
constexpr wchar_t kWindowTitle[] = L"XCNewEditor";
|
||||
constexpr float kClearColor[4] = { 0.08f, 0.09f, 0.11f, 1.0f };
|
||||
constexpr float kHostedPreviewClearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
constexpr float kNativeShellOuterMargin = 22.0f;
|
||||
constexpr float kNativeShellInnerGap = 18.0f;
|
||||
constexpr float kNativeShellHeaderHeight = 58.0f;
|
||||
constexpr float kNativeShellFooterHeight = 34.0f;
|
||||
constexpr float kNativePanelHeaderHeight = 42.0f;
|
||||
constexpr float kNativePanelPadding = 14.0f;
|
||||
constexpr float kNativePanelMinWidth = 260.0f;
|
||||
constexpr float kNativePanelMinHeight = 180.0f;
|
||||
|
||||
template <typename ResourceType>
|
||||
void ShutdownAndDelete(ResourceType*& resource) {
|
||||
@@ -78,6 +89,100 @@ const char* GetHostedPreviewStateLabel(
|
||||
}
|
||||
return "idle";
|
||||
}
|
||||
|
||||
bool ContainsPoint(const UI::UIRect& rect, const UI::UIPoint& point) {
|
||||
return point.x >= rect.x &&
|
||||
point.y >= rect.y &&
|
||||
point.x <= rect.x + rect.width &&
|
||||
point.y <= rect.y + rect.height;
|
||||
}
|
||||
|
||||
std::uint64_t MakeFrameTimestampNanoseconds() {
|
||||
return static_cast<std::uint64_t>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch())
|
||||
.count());
|
||||
}
|
||||
|
||||
void AppendDrawData(::XCEngine::UI::UIDrawData& destination, const ::XCEngine::UI::UIDrawData& source) {
|
||||
for (const ::XCEngine::UI::UIDrawList& drawList : source.GetDrawLists()) {
|
||||
destination.AddDrawList(drawList);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!canvasSession.validCanvas) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return canvasSession.hovered ||
|
||||
(canvasSession.windowFocused &&
|
||||
!previousFrame.stats.selectedElementId.empty());
|
||||
}
|
||||
|
||||
void PopulateKeyboardNavigationInput(
|
||||
::XCEngine::Editor::XCUIBackend::XCUILayoutLabInputState& input,
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta& frameDelta,
|
||||
bool captureKeyboardNavigation) {
|
||||
if (!captureKeyboardNavigation) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
struct NativeShellPanelLayout {
|
||||
Application::ShellPanelId panelId = Application::ShellPanelId::XCUIDemo;
|
||||
std::string title = {};
|
||||
UI::UIRect panelRect = {};
|
||||
UI::UIRect canvasRect = {};
|
||||
bool visible = false;
|
||||
bool hovered = false;
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
NativeShellPanelLayout MakePanelLayout(
|
||||
Application::ShellPanelId panelId,
|
||||
std::string title,
|
||||
const UI::UIRect& panelRect,
|
||||
const UI::UIPoint& pointerPosition,
|
||||
bool windowFocused,
|
||||
bool active) {
|
||||
NativeShellPanelLayout layout = {};
|
||||
layout.panelId = panelId;
|
||||
layout.title = std::move(title);
|
||||
layout.panelRect = panelRect;
|
||||
layout.canvasRect = UI::UIRect(
|
||||
panelRect.x + kNativePanelPadding,
|
||||
panelRect.y + kNativePanelHeaderHeight,
|
||||
(std::max)(0.0f, panelRect.width - kNativePanelPadding * 2.0f),
|
||||
(std::max)(0.0f, panelRect.height - kNativePanelHeaderHeight - kNativePanelPadding));
|
||||
layout.visible = panelRect.width >= kNativePanelMinWidth && panelRect.height >= kNativePanelMinHeight;
|
||||
layout.hovered = windowFocused && ContainsPoint(layout.canvasRect, pointerPosition);
|
||||
layout.active = active;
|
||||
return layout;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter>
|
||||
@@ -91,6 +196,22 @@ Application::CreateHostedPreviewPresenter(bool nativePreview) {
|
||||
return ::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIHostedPreviewPresenter();
|
||||
}
|
||||
|
||||
bool Application::IsNativeWindowHostEnabled() const {
|
||||
return m_windowHostMode == WindowHostMode::NativeXCUI;
|
||||
}
|
||||
|
||||
void Application::InitializeNativeShell() {
|
||||
m_nativeActivePanel = m_shellChromeState.IsPanelVisible(ShellPanelId::XCUIDemo)
|
||||
? ShellPanelId::XCUIDemo
|
||||
: ShellPanelId::XCUILayoutLab;
|
||||
m_nativeDemoInputBridge.Reset();
|
||||
m_nativeLayoutInputBridge.Reset();
|
||||
m_nativeDemoCanvasHost.ClearCanvasSession();
|
||||
m_nativeLayoutCanvasHost.ClearCanvasSession();
|
||||
m_nativeDemoReloadSucceeded = m_nativeDemoRuntime.ReloadDocuments();
|
||||
m_nativeLayoutReloadSucceeded = m_nativeLayoutRuntime.ReloadDocuments();
|
||||
}
|
||||
|
||||
const Application::ShellPanelChromeState* Application::TryGetShellPanelState(ShellPanelId panelId) const {
|
||||
return m_shellChromeState.TryGetPanelState(panelId);
|
||||
}
|
||||
@@ -197,20 +318,25 @@ void Application::ConfigureShellCommandRouter() {
|
||||
Application::RegisterShellViewCommands(m_shellCommandRouter, bindings);
|
||||
}
|
||||
|
||||
void Application::DispatchShellShortcuts() {
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeCaptureOptions options = {};
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot snapshot =
|
||||
m_xcuiInputSource.CaptureSnapshot(options);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
snapshot.wantCaptureKeyboard = io.WantCaptureKeyboard;
|
||||
snapshot.wantTextInput = io.WantTextInput;
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta
|
||||
Application::DispatchShellShortcuts(
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot& snapshot) {
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot shellSnapshot = snapshot;
|
||||
if (!IsNativeWindowHostEnabled()) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
shellSnapshot.wantCaptureKeyboard = io.WantCaptureKeyboard;
|
||||
shellSnapshot.wantTextInput = io.WantTextInput;
|
||||
}
|
||||
|
||||
if (!m_shellInputBridge.HasBaseline()) {
|
||||
m_shellInputBridge.Prime(shellSnapshot);
|
||||
}
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta frameDelta =
|
||||
m_shellInputBridge.Translate(snapshot);
|
||||
m_shellInputBridge.Translate(shellSnapshot);
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIEditorCommandInputSnapshot commandSnapshot =
|
||||
Application::BuildShellShortcutSnapshot(frameDelta);
|
||||
m_shellCommandRouter.InvokeMatchingShortcut({ &commandSnapshot });
|
||||
return frameDelta;
|
||||
}
|
||||
|
||||
Application::HostedPreviewPanelDiagnostics Application::BuildHostedPreviewPanelDiagnostics(
|
||||
@@ -293,15 +419,19 @@ int Application::Run(HINSTANCE instance, int nCmdShow) {
|
||||
}
|
||||
|
||||
InitializeWindowCompositor();
|
||||
m_demoPanel = std::make_unique<XCUIDemoPanel>(
|
||||
&m_xcuiInputSource,
|
||||
CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo)),
|
||||
::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost());
|
||||
m_layoutLabPanel = std::make_unique<XCUILayoutLabPanel>(
|
||||
&m_xcuiInputSource,
|
||||
CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab)),
|
||||
::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost());
|
||||
ConfigureHostedPreviewPresenters();
|
||||
if (IsNativeWindowHostEnabled()) {
|
||||
InitializeNativeShell();
|
||||
} else {
|
||||
m_demoPanel = std::make_unique<XCUIDemoPanel>(
|
||||
&m_xcuiInputSource,
|
||||
CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo)),
|
||||
::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost());
|
||||
m_layoutLabPanel = std::make_unique<XCUILayoutLabPanel>(
|
||||
&m_xcuiInputSource,
|
||||
CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab)),
|
||||
::XCEngine::Editor::XCUIBackend::CreateImGuiXCUIPanelCanvasHost());
|
||||
ConfigureHostedPreviewPresenters();
|
||||
}
|
||||
m_shellInputBridge.Reset();
|
||||
ConfigureShellCommandRouter();
|
||||
m_running = true;
|
||||
@@ -433,7 +563,9 @@ bool Application::InitializeRenderer() {
|
||||
}
|
||||
|
||||
void Application::InitializeWindowCompositor() {
|
||||
m_windowCompositor = ::XCEngine::Editor::XCUIBackend::CreateImGuiWindowUICompositor();
|
||||
m_windowCompositor = IsNativeWindowHostEnabled()
|
||||
? ::XCEngine::Editor::XCUIBackend::CreateNativeWindowUICompositor()
|
||||
: ::XCEngine::Editor::XCUIBackend::CreateImGuiWindowUICompositor();
|
||||
if (m_windowCompositor != nullptr) {
|
||||
m_windowCompositor->Initialize(
|
||||
m_hwnd,
|
||||
@@ -654,6 +786,525 @@ bool Application::RenderHostedPreviewOffscreenSurface(
|
||||
return true;
|
||||
}
|
||||
|
||||
::XCEngine::UI::UIDrawData Application::BuildNativeShellDrawData(
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot& shellSnapshot,
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta& shellFrameDelta) {
|
||||
::XCEngine::UI::UIDrawData composedDrawData = {};
|
||||
|
||||
RECT clientRect = {};
|
||||
if (!GetClientRect(m_hwnd, &clientRect)) {
|
||||
return composedDrawData;
|
||||
}
|
||||
|
||||
const float windowWidth = static_cast<float>(clientRect.right - clientRect.left);
|
||||
const float windowHeight = static_cast<float>(clientRect.bottom - clientRect.top);
|
||||
if (windowWidth <= 1.0f || windowHeight <= 1.0f) {
|
||||
return composedDrawData;
|
||||
}
|
||||
|
||||
const UI::UIRect shellRect(0.0f, 0.0f, windowWidth, windowHeight);
|
||||
const UI::UIColor shellBorderColor(40.0f / 255.0f, 54.0f / 255.0f, 74.0f / 255.0f, 1.0f);
|
||||
const UI::UIColor shellSurfaceColor(11.0f / 255.0f, 15.0f / 255.0f, 22.0f / 255.0f, 180.0f / 255.0f);
|
||||
const UI::UIColor panelSurfaceColor(9.0f / 255.0f, 13.0f / 255.0f, 18.0f / 255.0f, 212.0f / 255.0f);
|
||||
const UI::UIColor panelBorderColor(53.0f / 255.0f, 72.0f / 255.0f, 96.0f / 255.0f, 1.0f);
|
||||
const UI::UIColor panelAccentColor(84.0f / 255.0f, 176.0f / 255.0f, 244.0f / 255.0f, 1.0f);
|
||||
const UI::UIColor hoveredAccentColor(1.0f, 206.0f / 255.0f, 112.0f / 255.0f, 1.0f);
|
||||
const UI::UIColor textPrimary(232.0f / 255.0f, 238.0f / 255.0f, 246.0f / 255.0f, 1.0f);
|
||||
const UI::UIColor textSecondary(150.0f / 255.0f, 164.0f / 255.0f, 184.0f / 255.0f, 1.0f);
|
||||
const UI::UIColor textMuted(108.0f / 255.0f, 123.0f / 255.0f, 145.0f / 255.0f, 1.0f);
|
||||
|
||||
const float topBarY = kNativeShellOuterMargin;
|
||||
const UI::UIRect topBarRect(
|
||||
kNativeShellOuterMargin,
|
||||
topBarY,
|
||||
(std::max)(0.0f, windowWidth - kNativeShellOuterMargin * 2.0f),
|
||||
kNativeShellHeaderHeight);
|
||||
const UI::UIRect footerRect(
|
||||
kNativeShellOuterMargin,
|
||||
(std::max)(topBarRect.y + topBarRect.height + kNativeShellInnerGap, windowHeight - kNativeShellOuterMargin - kNativeShellFooterHeight),
|
||||
(std::max)(0.0f, windowWidth - kNativeShellOuterMargin * 2.0f),
|
||||
kNativeShellFooterHeight);
|
||||
|
||||
const float workspaceTop = topBarRect.y + topBarRect.height + kNativeShellInnerGap;
|
||||
const float workspaceBottom = footerRect.y - kNativeShellInnerGap;
|
||||
const UI::UIRect workspaceRect(
|
||||
kNativeShellOuterMargin,
|
||||
workspaceTop,
|
||||
(std::max)(0.0f, windowWidth - kNativeShellOuterMargin * 2.0f),
|
||||
(std::max)(0.0f, workspaceBottom - workspaceTop));
|
||||
|
||||
bool demoVisible = m_shellChromeState.IsPanelVisible(ShellPanelId::XCUIDemo);
|
||||
bool layoutVisible = m_shellChromeState.IsPanelVisible(ShellPanelId::XCUILayoutLab);
|
||||
if (m_nativeActivePanel == ShellPanelId::XCUIDemo && !demoVisible && layoutVisible) {
|
||||
m_nativeActivePanel = ShellPanelId::XCUILayoutLab;
|
||||
} else if (m_nativeActivePanel == ShellPanelId::XCUILayoutLab && !layoutVisible && demoVisible) {
|
||||
m_nativeActivePanel = ShellPanelId::XCUIDemo;
|
||||
}
|
||||
|
||||
std::vector<NativeShellPanelLayout> panelLayouts = {};
|
||||
panelLayouts.reserve(2u);
|
||||
if (demoVisible && layoutVisible) {
|
||||
const float leftWidth = (std::max)(
|
||||
kNativePanelMinWidth,
|
||||
(std::min)(workspaceRect.width * 0.60f, workspaceRect.width - kNativePanelMinWidth - kNativeShellInnerGap));
|
||||
const float rightWidth = (std::max)(0.0f, workspaceRect.width - leftWidth - kNativeShellInnerGap);
|
||||
panelLayouts.push_back(MakePanelLayout(
|
||||
ShellPanelId::XCUIDemo,
|
||||
"XCUI Demo",
|
||||
UI::UIRect(workspaceRect.x, workspaceRect.y, leftWidth, workspaceRect.height),
|
||||
shellSnapshot.pointerPosition,
|
||||
shellSnapshot.windowFocused,
|
||||
m_nativeActivePanel == ShellPanelId::XCUIDemo));
|
||||
panelLayouts.push_back(MakePanelLayout(
|
||||
ShellPanelId::XCUILayoutLab,
|
||||
"XCUI Layout Lab",
|
||||
UI::UIRect(workspaceRect.x + leftWidth + kNativeShellInnerGap, workspaceRect.y, rightWidth, workspaceRect.height),
|
||||
shellSnapshot.pointerPosition,
|
||||
shellSnapshot.windowFocused,
|
||||
m_nativeActivePanel == ShellPanelId::XCUILayoutLab));
|
||||
} else if (demoVisible) {
|
||||
panelLayouts.push_back(MakePanelLayout(
|
||||
ShellPanelId::XCUIDemo,
|
||||
"XCUI Demo",
|
||||
workspaceRect,
|
||||
shellSnapshot.pointerPosition,
|
||||
shellSnapshot.windowFocused,
|
||||
true));
|
||||
m_nativeActivePanel = ShellPanelId::XCUIDemo;
|
||||
} else if (layoutVisible) {
|
||||
panelLayouts.push_back(MakePanelLayout(
|
||||
ShellPanelId::XCUILayoutLab,
|
||||
"XCUI Layout Lab",
|
||||
workspaceRect,
|
||||
shellSnapshot.pointerPosition,
|
||||
shellSnapshot.windowFocused,
|
||||
true));
|
||||
m_nativeActivePanel = ShellPanelId::XCUILayoutLab;
|
||||
}
|
||||
|
||||
if (shellFrameDelta.pointer.pressed[0]) {
|
||||
for (const NativeShellPanelLayout& panelLayout : panelLayouts) {
|
||||
if (panelLayout.hovered) {
|
||||
m_nativeActivePanel = panelLayout.panelId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (NativeShellPanelLayout& panelLayout : panelLayouts) {
|
||||
panelLayout.active = panelLayout.panelId == m_nativeActivePanel;
|
||||
}
|
||||
}
|
||||
|
||||
::XCEngine::UI::UIDrawList& chromeBackground =
|
||||
composedDrawData.EmplaceDrawList("XCUI.NativeShell.Background");
|
||||
chromeBackground.AddFilledRect(shellRect, shellSurfaceColor, 0.0f);
|
||||
chromeBackground.AddFilledRect(topBarRect, UI::UIColor(12.0f / 255.0f, 18.0f / 255.0f, 26.0f / 255.0f, 230.0f / 255.0f), 14.0f);
|
||||
chromeBackground.AddRectOutline(topBarRect, shellBorderColor, 1.0f, 14.0f);
|
||||
chromeBackground.AddFilledRect(footerRect, UI::UIColor(12.0f / 255.0f, 18.0f / 255.0f, 26.0f / 255.0f, 214.0f / 255.0f), 12.0f);
|
||||
chromeBackground.AddRectOutline(footerRect, shellBorderColor, 1.0f, 12.0f);
|
||||
|
||||
if (panelLayouts.empty()) {
|
||||
const UI::UIRect emptyStateRect(
|
||||
workspaceRect.x,
|
||||
workspaceRect.y,
|
||||
workspaceRect.width,
|
||||
(std::max)(0.0f, workspaceRect.height));
|
||||
chromeBackground.AddFilledRect(emptyStateRect, panelSurfaceColor, 18.0f);
|
||||
chromeBackground.AddRectOutline(emptyStateRect, panelBorderColor, 1.0f, 18.0f);
|
||||
|
||||
::XCEngine::UI::UIDrawList& emptyForeground =
|
||||
composedDrawData.EmplaceDrawList("XCUI.NativeShell.EmptyState");
|
||||
emptyForeground.AddText(
|
||||
UI::UIPoint(emptyStateRect.x + 24.0f, emptyStateRect.y + 28.0f),
|
||||
"XCUI native shell is active, but both sandbox panels are hidden.",
|
||||
textPrimary);
|
||||
emptyForeground.AddText(
|
||||
UI::UIPoint(emptyStateRect.x + 24.0f, emptyStateRect.y + 50.0f),
|
||||
"Use Ctrl+1 or Ctrl+2 to bring a panel back.",
|
||||
textSecondary);
|
||||
return composedDrawData;
|
||||
}
|
||||
|
||||
for (const NativeShellPanelLayout& panelLayout : panelLayouts) {
|
||||
const UI::UIColor borderColor = panelLayout.active
|
||||
? panelAccentColor
|
||||
: (panelLayout.hovered ? hoveredAccentColor : panelBorderColor);
|
||||
chromeBackground.AddFilledRect(panelLayout.panelRect, panelSurfaceColor, 18.0f);
|
||||
chromeBackground.AddRectOutline(panelLayout.panelRect, borderColor, panelLayout.active ? 2.0f : 1.0f, 18.0f);
|
||||
chromeBackground.AddFilledRect(
|
||||
UI::UIRect(
|
||||
panelLayout.panelRect.x,
|
||||
panelLayout.panelRect.y,
|
||||
panelLayout.panelRect.width,
|
||||
kNativePanelHeaderHeight),
|
||||
UI::UIColor(13.0f / 255.0f, 20.0f / 255.0f, 28.0f / 255.0f, 242.0f / 255.0f),
|
||||
18.0f);
|
||||
}
|
||||
|
||||
struct NativePanelFrameSummary {
|
||||
NativeShellPanelLayout layout = {};
|
||||
std::string lineA = {};
|
||||
std::string lineB = {};
|
||||
::XCEngine::UI::UIDrawData overlay = {};
|
||||
};
|
||||
|
||||
std::vector<NativePanelFrameSummary> panelSummaries = {};
|
||||
panelSummaries.reserve(panelLayouts.size());
|
||||
|
||||
const auto capturePanelSnapshot =
|
||||
[this, &shellSnapshot](const NativeShellPanelLayout& panelLayout, bool wantsKeyboard) {
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeCaptureOptions options = {};
|
||||
options.timestampNanoseconds = shellSnapshot.timestampNanoseconds;
|
||||
options.windowFocused = shellSnapshot.windowFocused;
|
||||
options.hasPointerInsideOverride = true;
|
||||
options.pointerInsideOverride = panelLayout.hovered;
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot panelSnapshot =
|
||||
m_xcuiInputSource.CaptureSnapshot(options);
|
||||
if (!wantsKeyboard) {
|
||||
panelSnapshot.keys.clear();
|
||||
panelSnapshot.characters.clear();
|
||||
panelSnapshot.wantCaptureKeyboard = false;
|
||||
panelSnapshot.wantTextInput = false;
|
||||
}
|
||||
return panelSnapshot;
|
||||
};
|
||||
|
||||
const auto extractCanvasOverlay =
|
||||
[](const ::XCEngine::Editor::XCUIBackend::NativeXCUIPanelCanvasHost& canvasHost) {
|
||||
::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasFrameSnapshot snapshot = {};
|
||||
if (!canvasHost.TryGetLatestFrameSnapshot(snapshot)) {
|
||||
return ::XCEngine::UI::UIDrawData();
|
||||
}
|
||||
return snapshot.overlayDrawData;
|
||||
};
|
||||
|
||||
for (const NativeShellPanelLayout& panelLayout : panelLayouts) {
|
||||
if (panelLayout.panelId == ShellPanelId::XCUIDemo) {
|
||||
::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasSession canvasSession = {};
|
||||
canvasSession.hostRect = panelLayout.panelRect;
|
||||
canvasSession.canvasRect = panelLayout.canvasRect;
|
||||
canvasSession.pointerPosition = shellSnapshot.pointerPosition;
|
||||
canvasSession.validCanvas = panelLayout.canvasRect.width > 1.0f && panelLayout.canvasRect.height > 1.0f;
|
||||
canvasSession.hovered = panelLayout.hovered;
|
||||
canvasSession.windowFocused = shellSnapshot.windowFocused;
|
||||
m_nativeDemoCanvasHost.SetCanvasSession(canvasSession);
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasRequest canvasRequest = {};
|
||||
canvasRequest.childId = "XCUIDemo.NativeCanvas";
|
||||
canvasRequest.height = panelLayout.panelRect.height;
|
||||
canvasRequest.topInset = panelLayout.canvasRect.y - panelLayout.panelRect.y;
|
||||
canvasRequest.drawPreviewFrame = false;
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasSession resolvedSession =
|
||||
m_nativeDemoCanvasHost.BeginCanvas(canvasRequest);
|
||||
|
||||
const bool wantsKeyboard = panelLayout.active;
|
||||
const auto panelSnapshot = capturePanelSnapshot(panelLayout, wantsKeyboard);
|
||||
if (!m_nativeDemoInputBridge.HasBaseline()) {
|
||||
m_nativeDemoInputBridge.Prime(panelSnapshot);
|
||||
}
|
||||
const auto panelFrameDelta = m_nativeDemoInputBridge.Translate(panelSnapshot);
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUIDemoInputState input = {};
|
||||
input.canvasRect = resolvedSession.canvasRect;
|
||||
input.pointerPosition = panelSnapshot.pointerPosition;
|
||||
input.pointerInside = panelSnapshot.pointerInside;
|
||||
input.pointerPressed = panelFrameDelta.pointer.pressed[0];
|
||||
input.pointerReleased = panelFrameDelta.pointer.released[0];
|
||||
input.pointerDown = panelSnapshot.pointerButtonsDown[0];
|
||||
input.windowFocused = panelSnapshot.windowFocused;
|
||||
input.wantCaptureMouse = panelSnapshot.wantCaptureMouse;
|
||||
input.wantCaptureKeyboard = panelSnapshot.wantCaptureKeyboard;
|
||||
input.wantTextInput = panelSnapshot.wantTextInput;
|
||||
input.events = panelFrameDelta.events;
|
||||
|
||||
const auto& frame = m_nativeDemoRuntime.Update(input);
|
||||
AppendDrawData(composedDrawData, frame.drawData);
|
||||
|
||||
if (IsShellViewToggleEnabled(ShellViewToggleId::HostedPreviewHud)) {
|
||||
const auto& stats = frame.stats;
|
||||
const UI::UIRect hudRect(
|
||||
resolvedSession.canvasRect.x + 10.0f,
|
||||
resolvedSession.canvasRect.y + 10.0f,
|
||||
(std::min)(resolvedSession.canvasRect.width - 20.0f, 360.0f),
|
||||
62.0f);
|
||||
if (hudRect.width > 40.0f && hudRect.height > 20.0f) {
|
||||
m_nativeDemoCanvasHost.DrawFilledRect(
|
||||
hudRect,
|
||||
UI::UIColor(12.0f / 255.0f, 18.0f / 255.0f, 26.0f / 255.0f, 214.0f / 255.0f),
|
||||
10.0f);
|
||||
m_nativeDemoCanvasHost.DrawOutlineRect(hudRect, panelBorderColor, 1.0f, 10.0f);
|
||||
m_nativeDemoCanvasHost.DrawText(
|
||||
UI::UIPoint(hudRect.x + 10.0f, hudRect.y + 8.0f),
|
||||
"Direct native XCUI frame",
|
||||
textPrimary);
|
||||
m_nativeDemoCanvasHost.DrawText(
|
||||
UI::UIPoint(hudRect.x + 10.0f, hudRect.y + 28.0f),
|
||||
std::string("Tree ") + std::to_string(static_cast<unsigned long long>(stats.treeGeneration)) +
|
||||
" | Elements " + std::to_string(stats.elementCount) +
|
||||
" | Commands " + std::to_string(stats.commandCount),
|
||||
textSecondary);
|
||||
m_nativeDemoCanvasHost.DrawText(
|
||||
UI::UIPoint(hudRect.x + 10.0f, hudRect.y + 46.0f),
|
||||
stats.statusMessage,
|
||||
textMuted);
|
||||
}
|
||||
|
||||
const auto drawDebugRect =
|
||||
[this, &stats](const std::string& elementId, const UI::UIColor& color, const char* label) {
|
||||
if (elementId.empty()) {
|
||||
return;
|
||||
}
|
||||
UI::UIRect rect = {};
|
||||
if (!m_nativeDemoRuntime.TryGetElementRect(elementId, rect)) {
|
||||
return;
|
||||
}
|
||||
m_nativeDemoCanvasHost.DrawOutlineRect(rect, color, 2.0f, 6.0f);
|
||||
if (label != nullptr && label[0] != '\0') {
|
||||
m_nativeDemoCanvasHost.DrawText(UI::UIPoint(rect.x + 4.0f, rect.y + 4.0f), label, color);
|
||||
}
|
||||
};
|
||||
drawDebugRect(stats.hoveredElementId, UI::UIColor(1.0f, 195.0f / 255.0f, 64.0f / 255.0f, 1.0f), "hover");
|
||||
drawDebugRect(stats.focusedElementId, UI::UIColor(64.0f / 255.0f, 214.0f / 255.0f, 1.0f, 1.0f), "focus");
|
||||
}
|
||||
|
||||
m_nativeDemoCanvasHost.EndCanvas();
|
||||
|
||||
NativePanelFrameSummary summary = {};
|
||||
summary.layout = panelLayout;
|
||||
summary.lineA = m_nativeDemoReloadSucceeded
|
||||
? frame.stats.statusMessage
|
||||
: "Document reload failed; showing last retained runtime state.";
|
||||
summary.lineB =
|
||||
std::string(panelLayout.active ? "Active" : "Passive") +
|
||||
" | " + std::to_string(frame.stats.elementCount) +
|
||||
" elements | " + std::to_string(frame.stats.commandCount) +
|
||||
" cmds";
|
||||
summary.overlay = extractCanvasOverlay(m_nativeDemoCanvasHost);
|
||||
panelSummaries.push_back(std::move(summary));
|
||||
m_nativeDemoCanvasHost.ClearCanvasSession();
|
||||
continue;
|
||||
}
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasSession canvasSession = {};
|
||||
canvasSession.hostRect = panelLayout.panelRect;
|
||||
canvasSession.canvasRect = panelLayout.canvasRect;
|
||||
canvasSession.pointerPosition = shellSnapshot.pointerPosition;
|
||||
canvasSession.validCanvas = panelLayout.canvasRect.width > 1.0f && panelLayout.canvasRect.height > 1.0f;
|
||||
canvasSession.hovered = panelLayout.hovered;
|
||||
canvasSession.windowFocused = shellSnapshot.windowFocused;
|
||||
m_nativeLayoutCanvasHost.SetCanvasSession(canvasSession);
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUIPanelCanvasRequest canvasRequest = {};
|
||||
canvasRequest.childId = "XCUILayoutLab.NativeCanvas";
|
||||
canvasRequest.height = panelLayout.panelRect.height;
|
||||
canvasRequest.topInset = panelLayout.canvasRect.y - panelLayout.panelRect.y;
|
||||
canvasRequest.drawPreviewFrame = false;
|
||||
const auto resolvedSession = m_nativeLayoutCanvasHost.BeginCanvas(canvasRequest);
|
||||
|
||||
const bool wantsKeyboard = panelLayout.active;
|
||||
const auto panelSnapshot = capturePanelSnapshot(panelLayout, wantsKeyboard);
|
||||
if (!m_nativeLayoutInputBridge.HasBaseline()) {
|
||||
m_nativeLayoutInputBridge.Prime(panelSnapshot);
|
||||
}
|
||||
const auto panelFrameDelta = m_nativeLayoutInputBridge.Translate(panelSnapshot);
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUILayoutLabInputState input = {};
|
||||
input.canvasRect = resolvedSession.canvasRect;
|
||||
input.pointerPosition = panelSnapshot.pointerPosition;
|
||||
input.pointerInside = panelSnapshot.pointerInside;
|
||||
input.pointerPressed = input.pointerInside && panelFrameDelta.pointer.pressed[0];
|
||||
PopulateKeyboardNavigationInput(
|
||||
input,
|
||||
panelFrameDelta,
|
||||
panelLayout.active && ShouldCaptureKeyboardNavigation(resolvedSession, m_nativeLayoutRuntime.GetFrameResult()));
|
||||
|
||||
const auto& frame = m_nativeLayoutRuntime.Update(input);
|
||||
AppendDrawData(composedDrawData, frame.drawData);
|
||||
m_nativeLayoutCanvasHost.EndCanvas();
|
||||
|
||||
NativePanelFrameSummary summary = {};
|
||||
summary.layout = panelLayout;
|
||||
summary.lineA = m_nativeLayoutReloadSucceeded
|
||||
? frame.stats.statusMessage
|
||||
: "Layout lab reload failed; showing last retained runtime state.";
|
||||
summary.lineB =
|
||||
std::to_string(frame.stats.rowCount) + " rows | " +
|
||||
std::to_string(frame.stats.columnCount) + " cols | " +
|
||||
std::to_string(frame.stats.commandCount) + " cmds";
|
||||
summary.overlay = extractCanvasOverlay(m_nativeLayoutCanvasHost);
|
||||
panelSummaries.push_back(std::move(summary));
|
||||
m_nativeLayoutCanvasHost.ClearCanvasSession();
|
||||
}
|
||||
|
||||
::XCEngine::UI::UIDrawList& chromeForeground =
|
||||
composedDrawData.EmplaceDrawList("XCUI.NativeShell.Foreground");
|
||||
chromeForeground.AddText(
|
||||
UI::UIPoint(topBarRect.x + 18.0f, topBarRect.y + 14.0f),
|
||||
"XCUI Native Shell",
|
||||
textPrimary);
|
||||
chromeForeground.AddText(
|
||||
UI::UIPoint(topBarRect.x + 18.0f, topBarRect.y + 34.0f),
|
||||
"Default host path is now direct XCUI composition over the swapchain, with ImGui kept only as an explicit compatibility shell.",
|
||||
textSecondary);
|
||||
|
||||
std::ostringstream footerStream = {};
|
||||
footerStream
|
||||
<< "Ctrl+1 Demo | Ctrl+2 Layout | Ctrl+Shift+B Backdrop "
|
||||
<< "| Ctrl+Shift+H HUD | Active panel: "
|
||||
<< (m_nativeActivePanel == ShellPanelId::XCUIDemo ? "XCUI Demo" : "XCUI Layout Lab");
|
||||
chromeForeground.AddText(
|
||||
UI::UIPoint(footerRect.x + 14.0f, footerRect.y + 10.0f),
|
||||
footerStream.str(),
|
||||
textSecondary);
|
||||
|
||||
for (const NativePanelFrameSummary& summary : panelSummaries) {
|
||||
chromeForeground.AddText(
|
||||
UI::UIPoint(summary.layout.panelRect.x + 16.0f, summary.layout.panelRect.y + 12.0f),
|
||||
summary.layout.title,
|
||||
textPrimary);
|
||||
chromeForeground.AddText(
|
||||
UI::UIPoint(summary.layout.panelRect.x + 16.0f, summary.layout.panelRect.y + 28.0f),
|
||||
summary.lineA,
|
||||
textSecondary);
|
||||
chromeForeground.AddText(
|
||||
UI::UIPoint(summary.layout.panelRect.x + 16.0f, summary.layout.panelRect.y + summary.layout.panelRect.height - 18.0f),
|
||||
summary.lineB,
|
||||
textMuted);
|
||||
}
|
||||
|
||||
if (IsShellViewToggleEnabled(ShellViewToggleId::NativeXCUIOverlay)) {
|
||||
const UI::UIRect overlayRect(
|
||||
topBarRect.x + topBarRect.width - 282.0f,
|
||||
topBarRect.y + 10.0f,
|
||||
266.0f,
|
||||
38.0f);
|
||||
chromeForeground.AddFilledRect(
|
||||
overlayRect,
|
||||
UI::UIColor(18.0f / 255.0f, 72.0f / 255.0f, 112.0f / 255.0f, 196.0f / 255.0f),
|
||||
10.0f);
|
||||
chromeForeground.AddRectOutline(overlayRect, panelAccentColor, 1.0f, 10.0f);
|
||||
chromeForeground.AddText(
|
||||
UI::UIPoint(overlayRect.x + 12.0f, overlayRect.y + 12.0f),
|
||||
"Overlay: native compositor + direct XCUI packet",
|
||||
textPrimary);
|
||||
}
|
||||
|
||||
for (const NativePanelFrameSummary& summary : panelSummaries) {
|
||||
AppendDrawData(composedDrawData, summary.overlay);
|
||||
}
|
||||
|
||||
return composedDrawData;
|
||||
}
|
||||
|
||||
void Application::FrameLegacyImGuiHost() {
|
||||
m_hostedPreviewQueue.BeginFrame();
|
||||
m_hostedPreviewSurfaceRegistry.BeginFrame();
|
||||
SyncHostedPreviewSurfaces();
|
||||
if (m_windowCompositor == nullptr) {
|
||||
m_xcuiInputSource.ClearFrameTransients();
|
||||
return;
|
||||
}
|
||||
|
||||
m_windowCompositor->RenderFrame(
|
||||
kClearColor,
|
||||
[this]() {
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeCaptureOptions options = {};
|
||||
options.timestampNanoseconds = MakeFrameTimestampNanoseconds();
|
||||
options.windowFocused = m_xcuiInputSource.IsWindowFocused();
|
||||
const auto shellSnapshot = m_xcuiInputSource.CaptureSnapshot(options);
|
||||
DispatchShellShortcuts(shellSnapshot);
|
||||
RenderShellChrome();
|
||||
if (m_demoPanel) {
|
||||
m_demoPanel->RenderIfVisible();
|
||||
}
|
||||
if (m_layoutLabPanel) {
|
||||
m_layoutLabPanel->RenderIfVisible();
|
||||
}
|
||||
bool showImGuiDemoWindow = IsShellViewToggleEnabled(ShellViewToggleId::ImGuiDemoWindow);
|
||||
if (showImGuiDemoWindow) {
|
||||
ImGui::ShowDemoWindow(&showImGuiDemoWindow);
|
||||
SetShellViewToggleEnabled(ShellViewToggleId::ImGuiDemoWindow, showImGuiDemoWindow);
|
||||
}
|
||||
|
||||
SyncShellChromePanelStateFromPanels();
|
||||
SyncHostedPreviewSurfaces();
|
||||
},
|
||||
[this](
|
||||
const ::XCEngine::Rendering::RenderContext& renderContext,
|
||||
const ::XCEngine::Rendering::RenderSurface& surface) {
|
||||
RenderQueuedHostedPreviews(renderContext, surface);
|
||||
|
||||
if (!IsShellViewToggleEnabled(ShellViewToggleId::NativeBackdrop) &&
|
||||
!IsShellViewToggleEnabled(ShellViewToggleId::NativeXCUIOverlay)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MainWindowNativeBackdropRenderer::FrameState frameState = {};
|
||||
frameState.elapsedSeconds = static_cast<float>(
|
||||
std::chrono::duration<double>(std::chrono::steady_clock::now() - m_startTime).count());
|
||||
frameState.pulseAccent = IsShellViewToggleEnabled(ShellViewToggleId::PulseAccent);
|
||||
frameState.drawBackdrop = IsShellViewToggleEnabled(ShellViewToggleId::NativeBackdrop);
|
||||
if (IsShellViewToggleEnabled(ShellViewToggleId::NativeXCUIOverlay)) {
|
||||
const float width = static_cast<float>(surface.GetWidth());
|
||||
const float height = static_cast<float>(surface.GetHeight());
|
||||
const float horizontalMargin = (std::min)(width * 0.14f, 128.0f);
|
||||
const float topMargin = (std::min)(height * 0.15f, 132.0f);
|
||||
const float bottomMargin = (std::min)(height * 0.12f, 96.0f);
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUILayoutLabInputState overlayInput = {};
|
||||
overlayInput.canvasRect = ::XCEngine::UI::UIRect(
|
||||
horizontalMargin,
|
||||
topMargin,
|
||||
(std::max)(0.0f, width - horizontalMargin * 2.0f),
|
||||
(std::max)(0.0f, height - topMargin - bottomMargin));
|
||||
overlayInput.pointerPosition = m_xcuiInputSource.GetPointerPosition();
|
||||
overlayInput.pointerInside =
|
||||
overlayInput.pointerPosition.x >= overlayInput.canvasRect.x &&
|
||||
overlayInput.pointerPosition.y >= overlayInput.canvasRect.y &&
|
||||
overlayInput.pointerPosition.x <= overlayInput.canvasRect.x + overlayInput.canvasRect.width &&
|
||||
overlayInput.pointerPosition.y <= overlayInput.canvasRect.y + overlayInput.canvasRect.height;
|
||||
const auto& overlayFrame = m_nativeOverlayRuntime.Update(overlayInput);
|
||||
frameState.overlayDrawData = &overlayFrame.drawData;
|
||||
}
|
||||
m_nativeBackdropRenderer.Render(renderContext, surface, frameState);
|
||||
});
|
||||
|
||||
m_xcuiInputSource.ClearFrameTransients();
|
||||
}
|
||||
|
||||
void Application::FrameNativeXCUIHost() {
|
||||
auto* nativeCompositor =
|
||||
dynamic_cast<::XCEngine::Editor::XCUIBackend::NativeWindowUICompositor*>(m_windowCompositor.get());
|
||||
if (nativeCompositor == nullptr) {
|
||||
m_xcuiInputSource.ClearFrameTransients();
|
||||
return;
|
||||
}
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeCaptureOptions options = {};
|
||||
options.timestampNanoseconds = MakeFrameTimestampNanoseconds();
|
||||
options.windowFocused = m_xcuiInputSource.IsWindowFocused();
|
||||
const auto shellSnapshot = m_xcuiInputSource.CaptureSnapshot(options);
|
||||
const auto shellFrameDelta = DispatchShellShortcuts(shellSnapshot);
|
||||
::XCEngine::UI::UIDrawData nativeShellDrawData = BuildNativeShellDrawData(shellSnapshot, shellFrameDelta);
|
||||
nativeCompositor->SubmitRenderPacket(nativeShellDrawData, &m_hostedPreviewTextAtlasProvider);
|
||||
|
||||
m_windowCompositor->RenderFrame(
|
||||
kClearColor,
|
||||
{},
|
||||
[this](
|
||||
const ::XCEngine::Rendering::RenderContext& renderContext,
|
||||
const ::XCEngine::Rendering::RenderSurface& surface) {
|
||||
MainWindowNativeBackdropRenderer::FrameState frameState = {};
|
||||
frameState.elapsedSeconds = static_cast<float>(
|
||||
std::chrono::duration<double>(std::chrono::steady_clock::now() - m_startTime).count());
|
||||
frameState.pulseAccent = IsShellViewToggleEnabled(ShellViewToggleId::PulseAccent);
|
||||
frameState.drawBackdrop = IsShellViewToggleEnabled(ShellViewToggleId::NativeBackdrop);
|
||||
m_nativeBackdropRenderer.Render(renderContext, surface, frameState);
|
||||
});
|
||||
|
||||
m_xcuiInputSource.ClearFrameTransients();
|
||||
}
|
||||
|
||||
void Application::RenderShellChrome() {
|
||||
SyncShellChromePanelStateFromPanels();
|
||||
|
||||
@@ -1023,75 +1674,17 @@ void Application::Frame() {
|
||||
return;
|
||||
}
|
||||
|
||||
m_hostedPreviewQueue.BeginFrame();
|
||||
m_hostedPreviewSurfaceRegistry.BeginFrame();
|
||||
SyncHostedPreviewSurfaces();
|
||||
if (m_windowCompositor == nullptr) {
|
||||
m_xcuiInputSource.ClearFrameTransients();
|
||||
return;
|
||||
}
|
||||
|
||||
m_windowCompositor->RenderFrame(
|
||||
kClearColor,
|
||||
[this]() {
|
||||
DispatchShellShortcuts();
|
||||
RenderShellChrome();
|
||||
if (m_demoPanel) {
|
||||
m_demoPanel->RenderIfVisible();
|
||||
}
|
||||
if (m_layoutLabPanel) {
|
||||
m_layoutLabPanel->RenderIfVisible();
|
||||
}
|
||||
bool showImGuiDemoWindow = IsShellViewToggleEnabled(ShellViewToggleId::ImGuiDemoWindow);
|
||||
if (showImGuiDemoWindow) {
|
||||
ImGui::ShowDemoWindow(&showImGuiDemoWindow);
|
||||
SetShellViewToggleEnabled(ShellViewToggleId::ImGuiDemoWindow, showImGuiDemoWindow);
|
||||
}
|
||||
if (IsNativeWindowHostEnabled()) {
|
||||
FrameNativeXCUIHost();
|
||||
return;
|
||||
}
|
||||
|
||||
SyncShellChromePanelStateFromPanels();
|
||||
SyncHostedPreviewSurfaces();
|
||||
},
|
||||
[this](
|
||||
const ::XCEngine::Rendering::RenderContext& renderContext,
|
||||
const ::XCEngine::Rendering::RenderSurface& surface) {
|
||||
RenderQueuedHostedPreviews(renderContext, surface);
|
||||
|
||||
if (!IsShellViewToggleEnabled(ShellViewToggleId::NativeBackdrop) &&
|
||||
!IsShellViewToggleEnabled(ShellViewToggleId::NativeXCUIOverlay)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MainWindowNativeBackdropRenderer::FrameState frameState = {};
|
||||
frameState.elapsedSeconds = static_cast<float>(
|
||||
std::chrono::duration<double>(std::chrono::steady_clock::now() - m_startTime).count());
|
||||
frameState.pulseAccent = IsShellViewToggleEnabled(ShellViewToggleId::PulseAccent);
|
||||
frameState.drawBackdrop = IsShellViewToggleEnabled(ShellViewToggleId::NativeBackdrop);
|
||||
if (IsShellViewToggleEnabled(ShellViewToggleId::NativeXCUIOverlay)) {
|
||||
const float width = static_cast<float>(surface.GetWidth());
|
||||
const float height = static_cast<float>(surface.GetHeight());
|
||||
const float horizontalMargin = (std::min)(width * 0.14f, 128.0f);
|
||||
const float topMargin = (std::min)(height * 0.15f, 132.0f);
|
||||
const float bottomMargin = (std::min)(height * 0.12f, 96.0f);
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUILayoutLabInputState overlayInput = {};
|
||||
overlayInput.canvasRect = ::XCEngine::UI::UIRect(
|
||||
horizontalMargin,
|
||||
topMargin,
|
||||
(std::max)(0.0f, width - horizontalMargin * 2.0f),
|
||||
(std::max)(0.0f, height - topMargin - bottomMargin));
|
||||
overlayInput.pointerPosition = m_xcuiInputSource.GetPointerPosition();
|
||||
overlayInput.pointerInside =
|
||||
overlayInput.pointerPosition.x >= overlayInput.canvasRect.x &&
|
||||
overlayInput.pointerPosition.y >= overlayInput.canvasRect.y &&
|
||||
overlayInput.pointerPosition.x <= overlayInput.canvasRect.x + overlayInput.canvasRect.width &&
|
||||
overlayInput.pointerPosition.y <= overlayInput.canvasRect.y + overlayInput.canvasRect.height;
|
||||
const auto& overlayFrame = m_nativeOverlayRuntime.Update(overlayInput);
|
||||
frameState.overlayDrawData = &overlayFrame.drawData;
|
||||
}
|
||||
m_nativeBackdropRenderer.Render(renderContext, surface, frameState);
|
||||
});
|
||||
|
||||
m_xcuiInputSource.ClearFrameTransients();
|
||||
FrameLegacyImGuiHost();
|
||||
}
|
||||
|
||||
} // namespace NewEditor
|
||||
|
||||
Reference in New Issue
Block a user