Build XCEditor viewport input bridge foundation

This commit is contained in:
2026-04-07 04:53:24 +08:00
parent 93ceb61483
commit a53f47e561
11 changed files with 1400 additions and 0 deletions

View File

@@ -15,6 +15,7 @@ set(EDITOR_UI_UNIT_TEST_SOURCES
test_ui_editor_panel_frame.cpp
test_ui_editor_status_bar.cpp
test_ui_editor_tab_strip.cpp
test_ui_editor_viewport_input_bridge.cpp
test_ui_editor_viewport_slot.cpp
test_ui_editor_shortcut_manager.cpp
test_ui_editor_workspace_controller.cpp

View File

@@ -0,0 +1,196 @@
#include <gtest/gtest.h>
#include <XCEditor/Core/UIEditorViewportInputBridge.h>
namespace {
using XCEngine::UI::UIInputEvent;
using XCEngine::UI::UIInputEventType;
using XCEngine::UI::UIPoint;
using XCEngine::UI::UIPointerButton;
using XCEngine::UI::UIRect;
using XCEngine::UI::Editor::IsUIEditorViewportInputBridgeKeyDown;
using XCEngine::UI::Editor::IsUIEditorViewportInputBridgePointerButtonDown;
using XCEngine::UI::Editor::UIEditorViewportInputBridgeState;
using XCEngine::UI::Editor::UpdateUIEditorViewportInputBridge;
UIInputEvent MakePointerEvent(
UIInputEventType type,
float x,
float y,
UIPointerButton button = UIPointerButton::None) {
UIInputEvent event = {};
event.type = type;
event.position = UIPoint(x, y);
event.pointerButton = button;
return event;
}
UIInputEvent MakeKeyEvent(
UIInputEventType type,
std::int32_t keyCode) {
UIInputEvent event = {};
event.type = type;
event.keyCode = keyCode;
return event;
}
TEST(UIEditorViewportInputBridgeTest, PointerDownInsideStartsFocusAndCaptureAndTracksLocalPosition) {
UIEditorViewportInputBridgeState state = {};
const auto frame = UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{
MakePointerEvent(UIInputEventType::PointerMove, 220.0f, 280.0f),
MakePointerEvent(UIInputEventType::PointerButtonDown, 220.0f, 280.0f, UIPointerButton::Left)
});
EXPECT_TRUE(frame.hovered);
EXPECT_TRUE(frame.focused);
EXPECT_TRUE(frame.captured);
EXPECT_TRUE(frame.focusGained);
EXPECT_TRUE(frame.captureStarted);
EXPECT_TRUE(frame.pointerPressedInside);
EXPECT_FLOAT_EQ(frame.localPointerPosition.x, 120.0f);
EXPECT_FLOAT_EQ(frame.localPointerPosition.y, 80.0f);
EXPECT_TRUE(IsUIEditorViewportInputBridgePointerButtonDown(state, UIPointerButton::Left));
}
TEST(UIEditorViewportInputBridgeTest, FirstPointerMoveDoesNotCreateSyntheticDeltaFromOrigin) {
UIEditorViewportInputBridgeState state = {};
const auto frame = UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{
MakePointerEvent(UIInputEventType::PointerMove, 220.0f, 280.0f)
});
EXPECT_TRUE(frame.hovered);
EXPECT_FALSE(frame.pointerMoved);
EXPECT_FLOAT_EQ(frame.pointerDelta.x, 0.0f);
EXPECT_FLOAT_EQ(frame.pointerDelta.y, 0.0f);
EXPECT_FLOAT_EQ(frame.localPointerPosition.x, 120.0f);
EXPECT_FLOAT_EQ(frame.localPointerPosition.y, 80.0f);
}
TEST(UIEditorViewportInputBridgeTest, PointerUpEndsCaptureAndOutsidePointerDownClearsFocus) {
UIEditorViewportInputBridgeState state = {};
UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{
MakePointerEvent(UIInputEventType::PointerButtonDown, 220.0f, 280.0f, UIPointerButton::Left)
});
auto frame = UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{
MakePointerEvent(UIInputEventType::PointerButtonUp, 230.0f, 290.0f, UIPointerButton::Left)
});
EXPECT_TRUE(frame.pointerReleasedInside);
EXPECT_TRUE(frame.captureEnded);
EXPECT_FALSE(frame.captured);
frame = UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{
MakePointerEvent(UIInputEventType::PointerButtonDown, 40.0f, 60.0f, UIPointerButton::Left)
});
EXPECT_TRUE(frame.focusLost);
EXPECT_FALSE(frame.focused);
}
TEST(UIEditorViewportInputBridgeTest, PointerMoveWhileCapturedKeepsDeltaEvenOutsideSurface) {
UIEditorViewportInputBridgeState state = {};
UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{
MakePointerEvent(UIInputEventType::PointerButtonDown, 220.0f, 280.0f, UIPointerButton::Left)
});
const auto frame = UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{
MakePointerEvent(UIInputEventType::PointerMove, 60.0f, 120.0f)
});
EXPECT_TRUE(frame.pointerMoved);
EXPECT_FLOAT_EQ(frame.pointerDelta.x, -160.0f);
EXPECT_FLOAT_EQ(frame.pointerDelta.y, -160.0f);
EXPECT_FALSE(frame.hovered);
EXPECT_TRUE(frame.captured);
EXPECT_FLOAT_EQ(frame.localPointerPosition.x, -40.0f);
EXPECT_FLOAT_EQ(frame.localPointerPosition.y, -80.0f);
}
TEST(UIEditorViewportInputBridgeTest, WheelAndKeyboardAreAcceptedOnlyWhileFocused) {
UIEditorViewportInputBridgeState state = {};
auto frame = UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{
[] {
UIInputEvent wheel = {};
wheel.type = UIInputEventType::PointerWheel;
wheel.position = UIPoint(220.0f, 280.0f);
wheel.wheelDelta = 120.0f;
return wheel;
}(),
MakeKeyEvent(UIInputEventType::KeyDown, 87)
});
EXPECT_FLOAT_EQ(frame.wheelDelta, 120.0f);
EXPECT_TRUE(frame.pressedKeyCodes.empty());
frame = UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{
MakePointerEvent(UIInputEventType::PointerButtonDown, 220.0f, 280.0f, UIPointerButton::Left),
MakeKeyEvent(UIInputEventType::KeyDown, 87),
MakeKeyEvent(UIInputEventType::KeyUp, 87)
});
ASSERT_EQ(frame.pressedKeyCodes.size(), 1u);
ASSERT_EQ(frame.releasedKeyCodes.size(), 1u);
EXPECT_EQ(frame.pressedKeyCodes[0], 87);
EXPECT_EQ(frame.releasedKeyCodes[0], 87);
EXPECT_FALSE(IsUIEditorViewportInputBridgeKeyDown(state, 87));
}
TEST(UIEditorViewportInputBridgeTest, FocusLostClearsCapturedStateAndHeldKeys) {
UIEditorViewportInputBridgeState state = {};
UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{
MakePointerEvent(UIInputEventType::PointerButtonDown, 220.0f, 280.0f, UIPointerButton::Left),
MakeKeyEvent(UIInputEventType::KeyDown, 70)
});
UIInputEvent focusLost = {};
focusLost.type = UIInputEventType::FocusLost;
const auto frame =
UpdateUIEditorViewportInputBridge(
state,
UIRect(100.0f, 200.0f, 640.0f, 360.0f),
{ focusLost });
EXPECT_TRUE(frame.focusLost);
EXPECT_TRUE(frame.captureEnded);
EXPECT_FALSE(state.focused);
EXPECT_FALSE(state.captured);
EXPECT_FALSE(IsUIEditorViewportInputBridgeKeyDown(state, 70));
EXPECT_FALSE(IsUIEditorViewportInputBridgePointerButtonDown(state, UIPointerButton::Left));
}
} // namespace