Apply shared native shell layout in new editor
This commit is contained in:
@@ -128,6 +128,7 @@ Current gap:
|
||||
- routes shell shortcuts through the same command router without reading ImGui capture state in the default host path
|
||||
- drives both sandbox runtimes directly from Win32/XCUI input snapshots instead of routing through ImGui panel hosts
|
||||
- composes one native `UIDrawData` packet and submits it through `NativeWindowUICompositor`
|
||||
- The native shell layout policy now also lives behind `XCUINativeShellLayout`, so top-bar/footer/workspace geometry, panel split rules, and active-panel transfer on pointer press are no longer hard-coded inline inside `Application.cpp`.
|
||||
- `NativeXCUIPanelCanvasHost` now backs that direct shell path as an externally driven canvas/session host for native cards instead of assuming an ImGui child-window model, and it now emits native `Image` draw commands for hosted surface-image previews while preserving per-surface UVs.
|
||||
- `NativeWindowUICompositor` now creates and frees SRV-backed texture registrations for hosted preview surfaces, so native publication no longer depends on ImGui descriptor handles.
|
||||
- `Application` now runs the hosted-preview lifecycle in both legacy and native frame paths, treats published textures as XCUI-owned `UITextureHandle` state, queues native preview frames from `BuildNativeShellDrawData(...)`, and drains them during native rendering before shell chrome overlays.
|
||||
@@ -138,6 +139,7 @@ Current gap:
|
||||
|
||||
- The default shell host is now native, and the legacy ImGui shell/panel path has been split out of the default executable into the standalone `XCNewEditorImGuiCompat` compatibility slice.
|
||||
- The default native shell path is now split away from direct `ImGui::*` calls at the main-target header/include level and no longer links the compatibility slice by default.
|
||||
- The default native shell now also consumes shared `XCUINativeShellLayout` and `UIEditorPanelChrome` helpers for panel split/chrome policy instead of duplicating that card layout logic entirely inside `Application.cpp`.
|
||||
- The native shell currently proves direct runtime composition, but its shell chrome is still a bespoke `Application`-side layout rather than a fully shared XCUI-authored editor shell document.
|
||||
- Editor-specialized widgets are still incomplete at the shared-module level: the authored prototypes exist, but virtualization, multi-selection/focus traversal, toolbar/menu chrome, menu interaction widgets, and icon-atlas widgets are not yet extracted into reusable XCUI modules.
|
||||
- The default native text path now uses a standalone Windows/GDI atlas through `XCUIStandaloneTextAtlasProvider`, but that provider still lives inside `new_editor` and is not yet promoted into a shared/cross-platform text subsystem.
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "Application.h"
|
||||
#include "XCUIBackend/XCUINativeShellLayout.h"
|
||||
#include "XCUIBackend/NativeWindowUICompositor.h"
|
||||
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
#include <XCEngine/UI/Widgets/UIEditorPanelChrome.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@@ -20,14 +22,6 @@ 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) {
|
||||
@@ -40,13 +34,6 @@ void ShutdownAndDelete(ResourceType*& resource) {
|
||||
resource = nullptr;
|
||||
}
|
||||
|
||||
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>(
|
||||
@@ -102,37 +89,6 @@ void PopulateKeyboardNavigationInput(
|
||||
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
|
||||
|
||||
bool Application::IsNativeWindowHostEnabled() const {
|
||||
@@ -583,6 +539,15 @@ bool Application::RenderHostedPreviewOffscreenSurface(
|
||||
::XCEngine::UI::UIDrawData Application::BuildNativeShellDrawData(
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot& shellSnapshot,
|
||||
const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta& shellFrameDelta) {
|
||||
using NativeShellLayout = ::XCEngine::Editor::XCUIBackend::XCUINativeShellLayoutResult;
|
||||
using NativeShellMetrics = ::XCEngine::Editor::XCUIBackend::XCUINativeShellMetrics;
|
||||
using NativeShellPanelLayout = ::XCEngine::Editor::XCUIBackend::XCUINativeShellPanelLayout;
|
||||
using NativeShellPanelSpec = ::XCEngine::Editor::XCUIBackend::XCUINativeShellPanelSpec;
|
||||
using PanelChromeMetrics = ::XCEngine::UI::Widgets::UIEditorPanelChromeMetrics;
|
||||
using PanelChromePalette = ::XCEngine::UI::Widgets::UIEditorPanelChromePalette;
|
||||
using PanelChromeState = ::XCEngine::UI::Widgets::UIEditorPanelChromeState;
|
||||
using PanelChromeText = ::XCEngine::UI::Widgets::UIEditorPanelChromeText;
|
||||
|
||||
::XCEngine::UI::UIDrawData composedDrawData = {};
|
||||
|
||||
RECT clientRect = {};
|
||||
@@ -597,96 +562,42 @@ bool Application::RenderHostedPreviewOffscreenSurface(
|
||||
}
|
||||
|
||||
const UI::UIRect shellRect(0.0f, 0.0f, windowWidth, windowHeight);
|
||||
const NativeShellMetrics nativeShellMetrics = {};
|
||||
const PanelChromeMetrics panelChromeMetrics = {};
|
||||
const PanelChromePalette panelChromePalette = {};
|
||||
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 UI::UIColor& panelBorderColor = panelChromePalette.borderColor;
|
||||
const UI::UIColor& panelAccentColor = panelChromePalette.accentColor;
|
||||
const UI::UIColor& textPrimary = panelChromePalette.textPrimary;
|
||||
const UI::UIColor& textSecondary = panelChromePalette.textSecondary;
|
||||
const UI::UIColor& textMuted = panelChromePalette.textMuted;
|
||||
|
||||
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(
|
||||
const NativeShellLayout shellLayout = ::XCEngine::Editor::XCUIBackend::BuildXCUINativeShellLayout(
|
||||
shellRect,
|
||||
{
|
||||
NativeShellPanelSpec{
|
||||
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(
|
||||
m_shellChromeState.IsPanelVisible(ShellPanelId::XCUIDemo),
|
||||
},
|
||||
NativeShellPanelSpec{
|
||||
ShellPanelId::XCUILayoutLab,
|
||||
"XCUI Layout Lab",
|
||||
UI::UIRect(workspaceRect.x + leftWidth + kNativeShellInnerGap, workspaceRect.y, rightWidth, workspaceRect.height),
|
||||
m_shellChromeState.IsPanelVisible(ShellPanelId::XCUILayoutLab),
|
||||
},
|
||||
},
|
||||
m_nativeActivePanel,
|
||||
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;
|
||||
}
|
||||
shellFrameDelta.pointer.pressed[0],
|
||||
nativeShellMetrics);
|
||||
m_nativeActivePanel = shellLayout.activePanel;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
const UI::UIRect& topBarRect = shellLayout.topBarRect;
|
||||
const UI::UIRect& footerRect = shellLayout.footerRect;
|
||||
const UI::UIRect& workspaceRect = shellLayout.workspaceRect;
|
||||
const std::vector<NativeShellPanelLayout>& panelLayouts = shellLayout.panelLayouts;
|
||||
|
||||
::XCEngine::UI::UIDrawList& chromeBackground =
|
||||
composedDrawData.EmplaceDrawList("XCUI.NativeShell.Background");
|
||||
@@ -702,8 +613,12 @@ bool Application::RenderHostedPreviewOffscreenSurface(
|
||||
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::Widgets::AppendUIEditorPanelChromeBackground(
|
||||
chromeBackground,
|
||||
emptyStateRect,
|
||||
{},
|
||||
panelChromePalette,
|
||||
panelChromeMetrics);
|
||||
|
||||
::XCEngine::UI::UIDrawList& emptyForeground =
|
||||
composedDrawData.EmplaceDrawList("XCUI.NativeShell.EmptyState");
|
||||
@@ -719,19 +634,12 @@ bool Application::RenderHostedPreviewOffscreenSurface(
|
||||
}
|
||||
|
||||
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);
|
||||
::XCEngine::UI::Widgets::AppendUIEditorPanelChromeBackground(
|
||||
chromeBackground,
|
||||
panelLayout.panelRect,
|
||||
PanelChromeState{ panelLayout.active, panelLayout.hovered },
|
||||
panelChromePalette,
|
||||
panelChromeMetrics);
|
||||
}
|
||||
|
||||
struct NativePanelFrameSummary {
|
||||
@@ -1065,18 +973,16 @@ bool Application::RenderHostedPreviewOffscreenSurface(
|
||||
textSecondary);
|
||||
|
||||
for (const NativePanelFrameSummary& summary : panelSummaries) {
|
||||
chromeForeground.AddText(
|
||||
UI::UIPoint(summary.layout.panelRect.x + 16.0f, summary.layout.panelRect.y + 12.0f),
|
||||
::XCEngine::UI::Widgets::AppendUIEditorPanelChromeForeground(
|
||||
chromeForeground,
|
||||
summary.layout.panelRect,
|
||||
PanelChromeText{
|
||||
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);
|
||||
summary.lineB
|
||||
},
|
||||
panelChromePalette,
|
||||
panelChromeMetrics);
|
||||
}
|
||||
|
||||
if (IsShellViewToggleEnabled(ShellViewToggleId::NativeXCUIOverlay)) {
|
||||
|
||||
Reference in New Issue
Block a user