resources: formalize internal shader ir

This commit is contained in:
2026-04-07 11:31:13 +08:00
parent 1c87650fb3
commit 864438c508
11 changed files with 431 additions and 259 deletions

View File

@@ -12,9 +12,9 @@ using XCEngine::Input::KeyCode;
using XCEngine::UI::UIInputEvent;
using XCEngine::UI::UIInputEventType;
using XCEngine::UI::UIPoint;
using XCEngine::UI::UIRect;
using XCEngine::UI::UIPointerButton;
using XCEngine::UI::Editor::BuildDefaultUIEditorWorkspaceSession;
using XCEngine::UI::UIRect;
using XCEngine::UI::Editor::BuildDefaultUIEditorWorkspaceController;
using XCEngine::UI::Editor::BuildUIEditorWorkspacePanel;
using XCEngine::UI::Editor::BuildUIEditorWorkspaceSplit;
using XCEngine::UI::Editor::BuildUIEditorWorkspaceTabStack;
@@ -30,6 +30,7 @@ using XCEngine::UI::Editor::UIEditorShellInteractionMenuButtonRequest;
using XCEngine::UI::Editor::UIEditorShellInteractionModel;
using XCEngine::UI::Editor::UIEditorShellInteractionPopupItemRequest;
using XCEngine::UI::Editor::UIEditorShellInteractionState;
using XCEngine::UI::Editor::UIEditorWorkspaceController;
using XCEngine::UI::Editor::UIEditorWorkspaceModel;
using XCEngine::UI::Editor::UIEditorWorkspacePanelPresentationModel;
using XCEngine::UI::Editor::UIEditorWorkspaceSplitAxis;
@@ -149,6 +150,10 @@ UIEditorShellInteractionModel BuildInteractionModel() {
return model;
}
UIEditorWorkspaceController BuildController() {
return BuildDefaultUIEditorWorkspaceController(BuildPanelRegistry(), BuildWorkspace());
}
const UIEditorShellInteractionMenuButtonRequest* FindMenuButton(
const UIEditorShellInteractionFrame& frame,
std::string_view menuId) {
@@ -210,28 +215,21 @@ UIInputEvent MakeFocusLost() {
} // namespace
TEST(UIEditorShellInteractionTest, ClickMenuBarRootOpensSingleRootPopup) {
const auto registry = BuildPanelRegistry();
const auto workspace = BuildWorkspace();
const auto session = BuildDefaultUIEditorWorkspaceSession(registry, workspace);
auto controller = BuildController();
const auto model = BuildInteractionModel();
UIEditorShellInteractionState state = {};
const auto request = ResolveUIEditorShellInteractionRequest(
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
controller,
model,
{},
state);
ASSERT_EQ(request.menuButtons.size(), 2u);
const auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(RectCenter(request.menuButtons.front().rect)) });
@@ -243,18 +241,14 @@ TEST(UIEditorShellInteractionTest, ClickMenuBarRootOpensSingleRootPopup) {
}
TEST(UIEditorShellInteractionTest, HoverOtherRootSwitchesRootPopup) {
const auto registry = BuildPanelRegistry();
const auto workspace = BuildWorkspace();
const auto session = BuildDefaultUIEditorWorkspaceSession(registry, workspace);
auto controller = BuildController();
const auto model = BuildInteractionModel();
UIEditorShellInteractionState state = {};
auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(UIPoint(40.0f, 30.0f)) });
const auto* windowButton = FindMenuButton(frame, "window");
@@ -262,10 +256,8 @@ TEST(UIEditorShellInteractionTest, HoverOtherRootSwitchesRootPopup) {
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakePointerMove(RectCenter(windowButton->rect)) });
@@ -276,18 +268,14 @@ TEST(UIEditorShellInteractionTest, HoverOtherRootSwitchesRootPopup) {
}
TEST(UIEditorShellInteractionTest, HoverSubmenuOpensChildPopupAndEscapeCollapsesChain) {
const auto registry = BuildPanelRegistry();
const auto workspace = BuildWorkspace();
const auto session = BuildDefaultUIEditorWorkspaceSession(registry, workspace);
auto controller = BuildController();
const auto model = BuildInteractionModel();
UIEditorShellInteractionState state = {};
auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(UIPoint(40.0f, 30.0f)) });
const auto* submenuItem = FindPopupItem(frame, "file-workspace-tools");
@@ -296,10 +284,8 @@ TEST(UIEditorShellInteractionTest, HoverSubmenuOpensChildPopupAndEscapeCollapses
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakePointerMove(RectCenter(submenuItem->rect)) });
@@ -309,10 +295,8 @@ TEST(UIEditorShellInteractionTest, HoverSubmenuOpensChildPopupAndEscapeCollapses
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeKeyDown(KeyCode::Escape) });
EXPECT_EQ(frame.openRootMenuId, "file");
@@ -320,10 +304,8 @@ TEST(UIEditorShellInteractionTest, HoverSubmenuOpensChildPopupAndEscapeCollapses
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeKeyDown(KeyCode::Escape) });
EXPECT_FALSE(state.menuSession.HasOpenMenu());
@@ -331,18 +313,14 @@ TEST(UIEditorShellInteractionTest, HoverSubmenuOpensChildPopupAndEscapeCollapses
}
TEST(UIEditorShellInteractionTest, ClickCommandReturnsDispatchHookAndClosesMenu) {
const auto registry = BuildPanelRegistry();
const auto workspace = BuildWorkspace();
const auto session = BuildDefaultUIEditorWorkspaceSession(registry, workspace);
auto controller = BuildController();
const auto model = BuildInteractionModel();
UIEditorShellInteractionState state = {};
auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(UIPoint(40.0f, 30.0f)) });
const auto* commandItem = FindPopupItem(frame, "file-close");
@@ -350,10 +328,8 @@ TEST(UIEditorShellInteractionTest, ClickCommandReturnsDispatchHookAndClosesMenu)
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(RectCenter(commandItem->rect)) });
@@ -364,28 +340,22 @@ TEST(UIEditorShellInteractionTest, ClickCommandReturnsDispatchHookAndClosesMenu)
}
TEST(UIEditorShellInteractionTest, PointerDownOutsideDismissesWholeMenuChain) {
const auto registry = BuildPanelRegistry();
const auto workspace = BuildWorkspace();
const auto session = BuildDefaultUIEditorWorkspaceSession(registry, workspace);
auto controller = BuildController();
const auto model = BuildInteractionModel();
UIEditorShellInteractionState state = {};
auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(UIPoint(40.0f, 30.0f)) });
ASSERT_TRUE(state.menuSession.HasOpenMenu());
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(UIPoint(900.0f, 500.0f)) });
@@ -395,19 +365,15 @@ TEST(UIEditorShellInteractionTest, PointerDownOutsideDismissesWholeMenuChain) {
}
TEST(UIEditorShellInteractionTest, DisabledSubmenuDoesNotOpenChildPopup) {
const auto registry = BuildPanelRegistry();
const auto workspace = BuildWorkspace();
const auto session = BuildDefaultUIEditorWorkspaceSession(registry, workspace);
auto controller = BuildController();
auto model = BuildInteractionModel();
model.resolvedMenuModel.menus[0].items[0].enabled = false;
UIEditorShellInteractionState state = {};
auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(UIPoint(40.0f, 30.0f)) });
const auto* submenuItem = FindPopupItem(frame, "file-workspace-tools");
@@ -417,10 +383,8 @@ TEST(UIEditorShellInteractionTest, DisabledSubmenuDoesNotOpenChildPopup) {
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakePointerMove(RectCenter(submenuItem->rect)) });
@@ -430,18 +394,14 @@ TEST(UIEditorShellInteractionTest, DisabledSubmenuDoesNotOpenChildPopup) {
}
TEST(UIEditorShellInteractionTest, FocusLostDismissesWholeMenuChain) {
const auto registry = BuildPanelRegistry();
const auto workspace = BuildWorkspace();
const auto session = BuildDefaultUIEditorWorkspaceSession(registry, workspace);
auto controller = BuildController();
const auto model = BuildInteractionModel();
UIEditorShellInteractionState state = {};
auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(UIPoint(40.0f, 30.0f)) });
const auto* submenuItem = FindPopupItem(frame, "file-workspace-tools");
@@ -449,20 +409,16 @@ TEST(UIEditorShellInteractionTest, FocusLostDismissesWholeMenuChain) {
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakePointerMove(RectCenter(submenuItem->rect)) });
ASSERT_EQ(frame.request.popupRequests.size(), 2u);
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeFocusLost() });
@@ -474,18 +430,14 @@ TEST(UIEditorShellInteractionTest, FocusLostDismissesWholeMenuChain) {
}
TEST(UIEditorShellInteractionTest, OpenMenuConsumesWorkspacePointerDownForThatFrame) {
const auto registry = BuildPanelRegistry();
const auto workspace = BuildWorkspace();
const auto session = BuildDefaultUIEditorWorkspaceSession(registry, workspace);
auto controller = BuildController();
const auto model = BuildInteractionModel();
UIEditorShellInteractionState state = {};
auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(UIPoint(40.0f, 30.0f)) });
ASSERT_TRUE(state.menuSession.HasOpenMenu());
@@ -495,31 +447,100 @@ TEST(UIEditorShellInteractionTest, OpenMenuConsumesWorkspacePointerDownForThatFr
frame.shellFrame.workspaceFrame.viewportFrames.front().viewportShellFrame.slotLayout.inputRect;
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(RectCenter(inputRect)) });
EXPECT_FALSE(frame.result.workspaceResult.consumed);
EXPECT_FALSE(frame.shellFrame.workspaceFrame.viewportFrames.front()
.viewportShellFrame.inputFrame.pointerPressedInside);
EXPECT_FALSE(state.menuSession.HasOpenMenu());
}
TEST(UIEditorShellInteractionTest, InvalidResolvedMenuStateClosesInvisibleModalChain) {
const auto registry = BuildPanelRegistry();
const auto workspace = BuildWorkspace();
const auto session = BuildDefaultUIEditorWorkspaceSession(registry, workspace);
TEST(UIEditorShellInteractionTest, MenuClosedBubblesViewportCaptureFromWorkspaceInteraction) {
auto controller = BuildController();
const auto model = BuildInteractionModel();
UIEditorShellInteractionState state = {};
auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
model,
{});
ASSERT_FALSE(frame.shellFrame.workspaceFrame.viewportFrames.empty());
const UIRect inputRect =
frame.shellFrame.workspaceFrame.viewportFrames.front().viewportShellFrame.slotLayout.inputRect;
const UIPoint center = RectCenter(inputRect);
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
model,
{
MakePointerMove(center),
MakeLeftPointerDown(center)
});
EXPECT_TRUE(frame.result.consumed);
EXPECT_TRUE(frame.result.requestPointerCapture);
EXPECT_TRUE(frame.result.workspaceResult.requestPointerCapture);
EXPECT_EQ(frame.result.viewportPanelId, "scene");
EXPECT_TRUE(frame.result.viewportInputFrame.captureStarted);
}
TEST(UIEditorShellInteractionTest, ClosingMenuRestoresWorkspaceInteractionOnNextFrame) {
auto controller = BuildController();
const auto model = BuildInteractionModel();
UIEditorShellInteractionState state = {};
auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
model,
{ MakeLeftPointerDown(UIPoint(40.0f, 30.0f)) });
ASSERT_TRUE(state.menuSession.HasOpenMenu());
ASSERT_FALSE(frame.shellFrame.workspaceFrame.viewportFrames.empty());
const UIRect inputRect =
frame.shellFrame.workspaceFrame.viewportFrames.front().viewportShellFrame.slotLayout.inputRect;
const UIPoint center = RectCenter(inputRect);
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
model,
{ MakeLeftPointerDown(UIPoint(900.0f, 500.0f)) });
EXPECT_FALSE(state.menuSession.HasOpenMenu());
EXPECT_FALSE(frame.result.workspaceResult.consumed);
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
model,
{
MakePointerMove(center),
MakeLeftPointerDown(center)
});
EXPECT_TRUE(frame.result.workspaceResult.consumed);
EXPECT_TRUE(frame.result.requestPointerCapture);
EXPECT_EQ(frame.result.viewportPanelId, "scene");
}
TEST(UIEditorShellInteractionTest, InvalidResolvedMenuStateClosesInvisibleModalChain) {
auto controller = BuildController();
const auto model = BuildInteractionModel();
UIEditorShellInteractionState state = {};
auto frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
model,
{ MakeLeftPointerDown(UIPoint(40.0f, 30.0f)) });
ASSERT_TRUE(state.menuSession.HasOpenMenu());
@@ -530,10 +551,8 @@ TEST(UIEditorShellInteractionTest, InvalidResolvedMenuStateClosesInvisibleModalC
frame = UpdateUIEditorShellInteraction(
state,
controller,
UIRect(0.0f, 0.0f, 1280.0f, 720.0f),
registry,
workspace,
session,
updatedModel,
{});