feat(xcui): add tab strip and workspace compose foundations
This commit is contained in:
@@ -2,6 +2,8 @@ set(CORE_UI_TEST_SOURCES
|
||||
${CMAKE_SOURCE_DIR}/tests/UI/Core/unit/test_ui_shortcut_scope.cpp
|
||||
${CMAKE_SOURCE_DIR}/tests/UI/Core/unit/test_ui_splitter_layout.cpp
|
||||
${CMAKE_SOURCE_DIR}/tests/UI/Core/unit/test_ui_splitter_interaction.cpp
|
||||
${CMAKE_SOURCE_DIR}/tests/UI/Core/unit/test_ui_tab_strip_layout.cpp
|
||||
${CMAKE_SOURCE_DIR}/tests/UI/Core/unit/test_ui_tab_strip_model.cpp
|
||||
# Migration bridge: legacy XCUI unit coverage still lives under tests/Core/UI
|
||||
# until it is moved into tests/UI/Core/unit without changing behavior.
|
||||
${CMAKE_SOURCE_DIR}/tests/Core/UI/test_ui_core.cpp
|
||||
|
||||
72
tests/UI/Core/unit/test_ui_tab_strip_layout.cpp
Normal file
72
tests/UI/Core/unit/test_ui_tab_strip_layout.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEngine/UI/Layout/UITabStripLayout.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using XCEngine::UI::UIRect;
|
||||
using XCEngine::UI::UISize;
|
||||
using XCEngine::UI::Layout::ArrangeUITabStrip;
|
||||
using XCEngine::UI::Layout::MeasureUITabStrip;
|
||||
using XCEngine::UI::Layout::MeasureUITabStripHeaderWidth;
|
||||
using XCEngine::UI::Layout::UITabStripMeasureItem;
|
||||
using XCEngine::UI::Layout::UITabStripMetrics;
|
||||
|
||||
void ExpectRect(
|
||||
const UIRect& rect,
|
||||
float x,
|
||||
float y,
|
||||
float width,
|
||||
float height) {
|
||||
EXPECT_FLOAT_EQ(rect.x, x);
|
||||
EXPECT_FLOAT_EQ(rect.y, y);
|
||||
EXPECT_FLOAT_EQ(rect.width, width);
|
||||
EXPECT_FLOAT_EQ(rect.height, height);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(UITabStripLayoutTest, MeasureUsesTallestContentAndWidestHeaderBudget) {
|
||||
const UITabStripMetrics metrics = { 32.0f, 80.0f, 10.0f, 2.0f };
|
||||
const auto measured = MeasureUITabStrip(
|
||||
{
|
||||
UITabStripMeasureItem{ 36.0f, UISize(220.0f, 140.0f), UISize(120.0f, 80.0f) },
|
||||
UITabStripMeasureItem{ 96.0f, UISize(180.0f, 200.0f), UISize(160.0f, 90.0f) }
|
||||
},
|
||||
metrics);
|
||||
|
||||
const float desiredHeaderWidth =
|
||||
MeasureUITabStripHeaderWidth(36.0f, metrics) +
|
||||
MeasureUITabStripHeaderWidth(96.0f, metrics) +
|
||||
metrics.tabGap;
|
||||
const float minimumHeaderWidth = metrics.tabMinWidth * 2.0f + metrics.tabGap;
|
||||
|
||||
EXPECT_FLOAT_EQ(measured.desiredSize.width, 220.0f);
|
||||
EXPECT_FLOAT_EQ(measured.desiredSize.height, metrics.headerHeight + 200.0f);
|
||||
EXPECT_FLOAT_EQ(measured.minimumSize.width, minimumHeaderWidth);
|
||||
EXPECT_FLOAT_EQ(measured.minimumSize.height, metrics.headerHeight + 90.0f);
|
||||
}
|
||||
|
||||
TEST(UITabStripLayoutTest, MeasureWithoutItemsReturnsZeroSize) {
|
||||
const auto measured = MeasureUITabStrip({}, UITabStripMetrics{});
|
||||
|
||||
EXPECT_FLOAT_EQ(measured.desiredSize.width, 0.0f);
|
||||
EXPECT_FLOAT_EQ(measured.desiredSize.height, 0.0f);
|
||||
EXPECT_FLOAT_EQ(measured.minimumSize.width, 0.0f);
|
||||
EXPECT_FLOAT_EQ(measured.minimumSize.height, 0.0f);
|
||||
}
|
||||
|
||||
TEST(UITabStripLayoutTest, ArrangeScalesHeadersToAvailableWidthAndReservesContentArea) {
|
||||
const UITabStripMetrics metrics = { 30.0f, 72.0f, 12.0f, 4.0f };
|
||||
const auto arranged = ArrangeUITabStrip(
|
||||
UIRect(10.0f, 20.0f, 180.0f, 120.0f),
|
||||
{ 120.0f, 100.0f },
|
||||
metrics);
|
||||
|
||||
ExpectRect(arranged.headerRect, 10.0f, 20.0f, 180.0f, 30.0f);
|
||||
ExpectRect(arranged.contentRect, 10.0f, 50.0f, 180.0f, 90.0f);
|
||||
ASSERT_EQ(arranged.tabHeaderRects.size(), 2u);
|
||||
EXPECT_NEAR(arranged.tabHeaderRects[0].width + arranged.tabHeaderRects[1].width, 176.0f, 0.001f);
|
||||
ExpectRect(arranged.tabHeaderRects[0], 10.0f, 20.0f, 96.0f, 30.0f);
|
||||
ExpectRect(arranged.tabHeaderRects[1], 110.0f, 20.0f, 80.0f, 30.0f);
|
||||
}
|
||||
53
tests/UI/Core/unit/test_ui_tab_strip_model.cpp
Normal file
53
tests/UI/Core/unit/test_ui_tab_strip_model.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEngine/UI/Widgets/UITabStripModel.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using XCEngine::UI::Widgets::UITabStripModel;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(UITabStripModelTest, SetItemCountInitializesAndClampsSelection) {
|
||||
UITabStripModel model = {};
|
||||
|
||||
EXPECT_TRUE(model.SetItemCount(3u));
|
||||
EXPECT_TRUE(model.HasSelection());
|
||||
EXPECT_EQ(model.GetSelectedIndex(), 0u);
|
||||
|
||||
EXPECT_TRUE(model.SetSelectedIndex(2u));
|
||||
EXPECT_EQ(model.GetSelectedIndex(), 2u);
|
||||
|
||||
EXPECT_TRUE(model.SetItemCount(2u));
|
||||
EXPECT_EQ(model.GetSelectedIndex(), 1u);
|
||||
}
|
||||
|
||||
TEST(UITabStripModelTest, NextPreviousFirstAndLastStayWithinBounds) {
|
||||
UITabStripModel model = {};
|
||||
ASSERT_TRUE(model.SetItemCount(3u));
|
||||
|
||||
EXPECT_TRUE(model.SelectLast());
|
||||
EXPECT_EQ(model.GetSelectedIndex(), 2u);
|
||||
EXPECT_FALSE(model.SelectNext());
|
||||
EXPECT_EQ(model.GetSelectedIndex(), 2u);
|
||||
|
||||
EXPECT_TRUE(model.SelectPrevious());
|
||||
EXPECT_EQ(model.GetSelectedIndex(), 1u);
|
||||
EXPECT_TRUE(model.SelectFirst());
|
||||
EXPECT_EQ(model.GetSelectedIndex(), 0u);
|
||||
EXPECT_FALSE(model.SelectPrevious());
|
||||
EXPECT_EQ(model.GetSelectedIndex(), 0u);
|
||||
}
|
||||
|
||||
TEST(UITabStripModelTest, RejectsOutOfRangeSelectionAndClearsWhenEmpty) {
|
||||
UITabStripModel model = {};
|
||||
ASSERT_TRUE(model.SetItemCount(2u));
|
||||
|
||||
EXPECT_FALSE(model.SetSelectedIndex(3u));
|
||||
EXPECT_EQ(model.GetSelectedIndex(), 0u);
|
||||
|
||||
EXPECT_TRUE(model.SetItemCount(0u));
|
||||
EXPECT_FALSE(model.HasSelection());
|
||||
EXPECT_EQ(model.GetSelectedIndex(), UITabStripModel::InvalidIndex);
|
||||
EXPECT_FALSE(model.SetSelectedIndex(0u));
|
||||
}
|
||||
Reference in New Issue
Block a user