Add editor tree view widget contract
This commit is contained in:
@@ -20,6 +20,8 @@ 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_tree_view.cpp
|
||||
test_ui_editor_tree_view_interaction.cpp
|
||||
test_ui_editor_viewport_input_bridge.cpp
|
||||
test_ui_editor_viewport_shell.cpp
|
||||
test_ui_editor_viewport_slot.cpp
|
||||
|
||||
187
tests/UI/Editor/unit/test_ui_editor_tree_view.cpp
Normal file
187
tests/UI/Editor/unit/test_ui_editor_tree_view.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
#include <XCEngine/UI/Widgets/UIExpansionModel.h>
|
||||
#include <XCEngine/UI/Widgets/UISelectionModel.h>
|
||||
#include <XCEditor/Widgets/UIEditorTreeView.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using XCEngine::UI::UIDrawCommandType;
|
||||
using XCEngine::UI::UIDrawList;
|
||||
using XCEngine::UI::UIPoint;
|
||||
using XCEngine::UI::UIRect;
|
||||
using XCEngine::UI::Widgets::UIExpansionModel;
|
||||
using XCEngine::UI::Widgets::UISelectionModel;
|
||||
using XCEngine::UI::Editor::Widgets::AppendUIEditorTreeViewBackground;
|
||||
using XCEngine::UI::Editor::Widgets::AppendUIEditorTreeViewForeground;
|
||||
using XCEngine::UI::Editor::Widgets::BuildUIEditorTreeViewLayout;
|
||||
using XCEngine::UI::Editor::Widgets::CollectUIEditorTreeViewVisibleItemIndices;
|
||||
using XCEngine::UI::Editor::Widgets::DoesUIEditorTreeViewItemHaveChildren;
|
||||
using XCEngine::UI::Editor::Widgets::FindUIEditorTreeViewFirstVisibleChildItemIndex;
|
||||
using XCEngine::UI::Editor::Widgets::FindUIEditorTreeViewItemIndex;
|
||||
using XCEngine::UI::Editor::Widgets::FindUIEditorTreeViewParentItemIndex;
|
||||
using XCEngine::UI::Editor::Widgets::HitTestUIEditorTreeView;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorTreeViewHitTargetKind;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorTreeViewItem;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorTreeViewInvalidIndex;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorTreeViewLayout;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorTreeViewMetrics;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorTreeViewState;
|
||||
|
||||
bool ContainsTextCommand(const UIDrawList& drawList, std::string_view text) {
|
||||
for (const auto& command : drawList.GetCommands()) {
|
||||
if (command.type == UIDrawCommandType::Text && command.text == text) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<UIEditorTreeViewItem> BuildTreeItems() {
|
||||
return {
|
||||
{ "scene", "Scene", 0u, false, 0.0f },
|
||||
{ "camera", "Camera", 1u, true, 0.0f },
|
||||
{ "lights", "Lights", 1u, false, 0.0f },
|
||||
{ "sun", "Directional Light", 2u, true, 0.0f },
|
||||
{ "ui", "UI Root", 0u, false, 0.0f },
|
||||
{ "canvas", "Canvas", 1u, true, 0.0f }
|
||||
};
|
||||
}
|
||||
|
||||
TEST(UIEditorTreeViewTest, ChildDetectionUsesFlatHierarchyDepthRules) {
|
||||
const std::vector<UIEditorTreeViewItem> items = BuildTreeItems();
|
||||
|
||||
EXPECT_TRUE(DoesUIEditorTreeViewItemHaveChildren(items, 0u));
|
||||
EXPECT_FALSE(DoesUIEditorTreeViewItemHaveChildren(items, 1u));
|
||||
EXPECT_TRUE(DoesUIEditorTreeViewItemHaveChildren(items, 2u));
|
||||
EXPECT_TRUE(DoesUIEditorTreeViewItemHaveChildren(items, 4u));
|
||||
|
||||
EXPECT_EQ(FindUIEditorTreeViewItemIndex(items, "lights"), 2u);
|
||||
EXPECT_EQ(FindUIEditorTreeViewParentItemIndex(items, 0u), UIEditorTreeViewInvalidIndex);
|
||||
EXPECT_EQ(FindUIEditorTreeViewParentItemIndex(items, 1u), 0u);
|
||||
EXPECT_EQ(FindUIEditorTreeViewParentItemIndex(items, 3u), 2u);
|
||||
}
|
||||
|
||||
TEST(UIEditorTreeViewTest, VisibleItemsFollowExpansionModel) {
|
||||
const std::vector<UIEditorTreeViewItem> items = BuildTreeItems();
|
||||
|
||||
UIExpansionModel expansionModel = {};
|
||||
EXPECT_EQ(
|
||||
FindUIEditorTreeViewFirstVisibleChildItemIndex(items, expansionModel, 0u),
|
||||
UIEditorTreeViewInvalidIndex);
|
||||
EXPECT_EQ(
|
||||
CollectUIEditorTreeViewVisibleItemIndices(items, expansionModel),
|
||||
std::vector<std::size_t>({ 0u, 4u }));
|
||||
|
||||
expansionModel.Expand("scene");
|
||||
EXPECT_EQ(
|
||||
FindUIEditorTreeViewFirstVisibleChildItemIndex(items, expansionModel, 0u),
|
||||
1u);
|
||||
EXPECT_EQ(
|
||||
CollectUIEditorTreeViewVisibleItemIndices(items, expansionModel),
|
||||
std::vector<std::size_t>({ 0u, 1u, 2u, 4u }));
|
||||
|
||||
expansionModel.Expand("lights");
|
||||
expansionModel.Expand("ui");
|
||||
EXPECT_EQ(
|
||||
FindUIEditorTreeViewFirstVisibleChildItemIndex(items, expansionModel, 2u),
|
||||
3u);
|
||||
EXPECT_EQ(
|
||||
CollectUIEditorTreeViewVisibleItemIndices(items, expansionModel),
|
||||
std::vector<std::size_t>({ 0u, 1u, 2u, 3u, 4u, 5u }));
|
||||
}
|
||||
|
||||
TEST(UIEditorTreeViewTest, LayoutBuildsIndentedDisclosureAndLabelRects) {
|
||||
const std::vector<UIEditorTreeViewItem> items = BuildTreeItems();
|
||||
UIExpansionModel expansionModel = {};
|
||||
expansionModel.Expand("scene");
|
||||
|
||||
UIEditorTreeViewMetrics metrics = {};
|
||||
metrics.rowHeight = 24.0f;
|
||||
metrics.rowGap = 4.0f;
|
||||
metrics.horizontalPadding = 10.0f;
|
||||
metrics.indentWidth = 20.0f;
|
||||
metrics.disclosureExtent = 10.0f;
|
||||
metrics.disclosureLabelGap = 6.0f;
|
||||
|
||||
const UIEditorTreeViewLayout layout =
|
||||
BuildUIEditorTreeViewLayout(UIRect(20.0f, 30.0f, 280.0f, 240.0f), items, expansionModel, metrics);
|
||||
|
||||
ASSERT_EQ(layout.visibleItemIndices.size(), 4u);
|
||||
EXPECT_EQ(layout.visibleItemIndices[0], 0u);
|
||||
EXPECT_EQ(layout.visibleItemIndices[1], 1u);
|
||||
EXPECT_EQ(layout.visibleItemIndices[2], 2u);
|
||||
EXPECT_EQ(layout.visibleItemIndices[3], 4u);
|
||||
|
||||
EXPECT_FLOAT_EQ(layout.rowRects[0].x, 20.0f);
|
||||
EXPECT_FLOAT_EQ(layout.rowRects[0].y, 30.0f);
|
||||
EXPECT_FLOAT_EQ(layout.rowRects[0].height, 24.0f);
|
||||
|
||||
EXPECT_FLOAT_EQ(layout.disclosureRects[0].x, 30.0f);
|
||||
EXPECT_FLOAT_EQ(layout.disclosureRects[1].x, 50.0f);
|
||||
EXPECT_FLOAT_EQ(layout.disclosureRects[2].x, 50.0f);
|
||||
EXPECT_FLOAT_EQ(layout.labelRects[0].x, 46.0f);
|
||||
EXPECT_FLOAT_EQ(layout.labelRects[1].x, 66.0f);
|
||||
EXPECT_TRUE(layout.itemHasChildren[0]);
|
||||
EXPECT_FALSE(layout.itemHasChildren[1]);
|
||||
EXPECT_TRUE(layout.itemExpanded[0]);
|
||||
EXPECT_FALSE(layout.itemExpanded[2]);
|
||||
}
|
||||
|
||||
TEST(UIEditorTreeViewTest, HitTestPrioritizesDisclosureBeforeRow) {
|
||||
const std::vector<UIEditorTreeViewItem> items = BuildTreeItems();
|
||||
UIExpansionModel expansionModel = {};
|
||||
expansionModel.Expand("scene");
|
||||
|
||||
const UIEditorTreeViewLayout layout =
|
||||
BuildUIEditorTreeViewLayout(UIRect(20.0f, 30.0f, 280.0f, 240.0f), items, expansionModel);
|
||||
|
||||
const auto disclosureHit = HitTestUIEditorTreeView(layout, UIPoint(34.0f, 44.0f));
|
||||
EXPECT_EQ(disclosureHit.kind, UIEditorTreeViewHitTargetKind::Disclosure);
|
||||
EXPECT_EQ(disclosureHit.itemIndex, 0u);
|
||||
|
||||
const auto rowHit = HitTestUIEditorTreeView(layout, UIPoint(88.0f, 44.0f));
|
||||
EXPECT_EQ(rowHit.kind, UIEditorTreeViewHitTargetKind::Row);
|
||||
EXPECT_EQ(rowHit.itemIndex, 0u);
|
||||
|
||||
const auto emptyHit = HitTestUIEditorTreeView(layout, UIPoint(12.0f, 18.0f));
|
||||
EXPECT_EQ(emptyHit.kind, UIEditorTreeViewHitTargetKind::None);
|
||||
}
|
||||
|
||||
TEST(UIEditorTreeViewTest, BackgroundAndForegroundEmitStableCommands) {
|
||||
const std::vector<UIEditorTreeViewItem> items = BuildTreeItems();
|
||||
UIExpansionModel expansionModel = {};
|
||||
expansionModel.Expand("scene");
|
||||
expansionModel.Expand("ui");
|
||||
|
||||
UISelectionModel selectionModel = {};
|
||||
selectionModel.SetSelection("camera");
|
||||
|
||||
UIEditorTreeViewState state = {};
|
||||
state.hoveredItemId = "lights";
|
||||
state.focused = true;
|
||||
|
||||
const UIEditorTreeViewLayout layout =
|
||||
BuildUIEditorTreeViewLayout(UIRect(20.0f, 30.0f, 280.0f, 240.0f), items, expansionModel);
|
||||
|
||||
UIDrawList background("TreeViewBackground");
|
||||
AppendUIEditorTreeViewBackground(background, layout, items, selectionModel, state);
|
||||
ASSERT_EQ(background.GetCommandCount(), 4u);
|
||||
EXPECT_EQ(background.GetCommands()[0].type, UIDrawCommandType::FilledRect);
|
||||
EXPECT_EQ(background.GetCommands()[1].type, UIDrawCommandType::RectOutline);
|
||||
EXPECT_EQ(background.GetCommands()[2].type, UIDrawCommandType::FilledRect);
|
||||
EXPECT_EQ(background.GetCommands()[3].type, UIDrawCommandType::FilledRect);
|
||||
|
||||
UIDrawList foreground("TreeViewForeground");
|
||||
AppendUIEditorTreeViewForeground(foreground, layout, items);
|
||||
ASSERT_EQ(foreground.GetCommandCount(), 20u);
|
||||
EXPECT_EQ(foreground.GetCommands()[0].type, UIDrawCommandType::PushClipRect);
|
||||
EXPECT_TRUE(ContainsTextCommand(foreground, "v"));
|
||||
EXPECT_TRUE(ContainsTextCommand(foreground, "Scene"));
|
||||
EXPECT_TRUE(ContainsTextCommand(foreground, "Camera"));
|
||||
EXPECT_EQ(foreground.GetCommands()[19].type, UIDrawCommandType::PopClipRect);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
235
tests/UI/Editor/unit/test_ui_editor_tree_view_interaction.cpp
Normal file
235
tests/UI/Editor/unit/test_ui_editor_tree_view_interaction.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEditor/Core/UIEditorTreeViewInteraction.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::Widgets::UIExpansionModel;
|
||||
using XCEngine::UI::Widgets::UISelectionModel;
|
||||
using XCEngine::UI::Editor::UIEditorTreeViewInteractionState;
|
||||
using XCEngine::UI::Editor::UpdateUIEditorTreeViewInteraction;
|
||||
using XCEngine::UI::Editor::Widgets::BuildUIEditorTreeViewLayout;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorTreeViewHitTargetKind;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorTreeViewItem;
|
||||
|
||||
std::vector<UIEditorTreeViewItem> BuildTreeItems() {
|
||||
return {
|
||||
{ "scene", "Scene", 0u, false, 0.0f },
|
||||
{ "camera", "Camera", 1u, true, 0.0f },
|
||||
{ "lights", "Lights", 1u, false, 0.0f },
|
||||
{ "sun", "Directional Light", 2u, true, 0.0f },
|
||||
{ "ui", "UI Root", 0u, false, 0.0f },
|
||||
{ "canvas", "Canvas", 1u, true, 0.0f }
|
||||
};
|
||||
}
|
||||
|
||||
UIInputEvent MakePointerMove(float x, float y) {
|
||||
UIInputEvent event = {};
|
||||
event.type = UIInputEventType::PointerMove;
|
||||
event.position = UIPoint(x, y);
|
||||
return event;
|
||||
}
|
||||
|
||||
UIInputEvent MakePointerDown(float x, float y, UIPointerButton button = UIPointerButton::Left) {
|
||||
UIInputEvent event = {};
|
||||
event.type = UIInputEventType::PointerButtonDown;
|
||||
event.position = UIPoint(x, y);
|
||||
event.pointerButton = button;
|
||||
return event;
|
||||
}
|
||||
|
||||
UIInputEvent MakePointerUp(float x, float y, UIPointerButton button = UIPointerButton::Left) {
|
||||
UIInputEvent event = {};
|
||||
event.type = UIInputEventType::PointerButtonUp;
|
||||
event.position = UIPoint(x, y);
|
||||
event.pointerButton = button;
|
||||
return event;
|
||||
}
|
||||
|
||||
UIInputEvent MakePointerLeave() {
|
||||
UIInputEvent event = {};
|
||||
event.type = UIInputEventType::PointerLeave;
|
||||
return event;
|
||||
}
|
||||
|
||||
UIInputEvent MakeFocusLost() {
|
||||
UIInputEvent event = {};
|
||||
event.type = UIInputEventType::FocusLost;
|
||||
return event;
|
||||
}
|
||||
|
||||
UIPoint RectCenter(const XCEngine::UI::UIRect& rect) {
|
||||
return UIPoint(rect.x + rect.width * 0.5f, rect.y + rect.height * 0.5f);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(UIEditorTreeViewInteractionTest, PointerMoveUpdatesHoveredItemAndHitTarget) {
|
||||
const auto items = BuildTreeItems();
|
||||
UISelectionModel selectionModel = {};
|
||||
UIExpansionModel expansionModel = {};
|
||||
expansionModel.Expand("scene");
|
||||
UIEditorTreeViewInteractionState state = {};
|
||||
|
||||
const auto initialFrame = UpdateUIEditorTreeViewInteraction(
|
||||
state,
|
||||
selectionModel,
|
||||
expansionModel,
|
||||
UIRect(0.0f, 0.0f, 320.0f, 240.0f),
|
||||
items,
|
||||
{});
|
||||
const UIPoint lightsCenter = RectCenter(initialFrame.layout.rowRects[2]);
|
||||
|
||||
const auto frame = UpdateUIEditorTreeViewInteraction(
|
||||
state,
|
||||
selectionModel,
|
||||
expansionModel,
|
||||
UIRect(0.0f, 0.0f, 320.0f, 240.0f),
|
||||
items,
|
||||
{ MakePointerMove(lightsCenter.x, lightsCenter.y) });
|
||||
|
||||
EXPECT_EQ(frame.result.hitTarget.kind, UIEditorTreeViewHitTargetKind::Row);
|
||||
EXPECT_EQ(frame.result.hitTarget.itemIndex, 2u);
|
||||
EXPECT_EQ(state.treeViewState.hoveredItemId, "lights");
|
||||
}
|
||||
|
||||
TEST(UIEditorTreeViewInteractionTest, LeftClickRowSelectsItemAndFocusesTree) {
|
||||
const auto items = BuildTreeItems();
|
||||
UISelectionModel selectionModel = {};
|
||||
UIExpansionModel expansionModel = {};
|
||||
expansionModel.Expand("scene");
|
||||
UIEditorTreeViewInteractionState state = {};
|
||||
|
||||
const auto initialFrame = UpdateUIEditorTreeViewInteraction(
|
||||
state,
|
||||
selectionModel,
|
||||
expansionModel,
|
||||
UIRect(0.0f, 0.0f, 320.0f, 240.0f),
|
||||
items,
|
||||
{});
|
||||
const UIPoint cameraCenter = RectCenter(initialFrame.layout.rowRects[1]);
|
||||
|
||||
const auto frame = UpdateUIEditorTreeViewInteraction(
|
||||
state,
|
||||
selectionModel,
|
||||
expansionModel,
|
||||
UIRect(0.0f, 0.0f, 320.0f, 240.0f),
|
||||
items,
|
||||
{
|
||||
MakePointerDown(cameraCenter.x, cameraCenter.y),
|
||||
MakePointerUp(cameraCenter.x, cameraCenter.y)
|
||||
});
|
||||
|
||||
EXPECT_TRUE(frame.result.consumed);
|
||||
EXPECT_TRUE(frame.result.selectionChanged);
|
||||
EXPECT_EQ(frame.result.selectedItemId, "camera");
|
||||
EXPECT_TRUE(selectionModel.IsSelected("camera"));
|
||||
EXPECT_TRUE(state.treeViewState.focused);
|
||||
}
|
||||
|
||||
TEST(UIEditorTreeViewInteractionTest, LeftClickDisclosureTogglesExpansionAndRebuildsLayout) {
|
||||
const auto items = BuildTreeItems();
|
||||
UISelectionModel selectionModel = {};
|
||||
UIExpansionModel expansionModel = {};
|
||||
expansionModel.Expand("scene");
|
||||
UIEditorTreeViewInteractionState state = {};
|
||||
|
||||
const auto initialFrame = UpdateUIEditorTreeViewInteraction(
|
||||
state,
|
||||
selectionModel,
|
||||
expansionModel,
|
||||
UIRect(0.0f, 0.0f, 320.0f, 240.0f),
|
||||
items,
|
||||
{});
|
||||
const UIPoint lightsDisclosureCenter = RectCenter(initialFrame.layout.disclosureRects[2]);
|
||||
|
||||
const auto frame = UpdateUIEditorTreeViewInteraction(
|
||||
state,
|
||||
selectionModel,
|
||||
expansionModel,
|
||||
UIRect(0.0f, 0.0f, 320.0f, 240.0f),
|
||||
items,
|
||||
{
|
||||
MakePointerDown(lightsDisclosureCenter.x, lightsDisclosureCenter.y),
|
||||
MakePointerUp(lightsDisclosureCenter.x, lightsDisclosureCenter.y)
|
||||
});
|
||||
|
||||
EXPECT_TRUE(frame.result.consumed);
|
||||
EXPECT_TRUE(frame.result.expansionChanged);
|
||||
EXPECT_EQ(frame.result.toggledItemId, "lights");
|
||||
EXPECT_TRUE(expansionModel.IsExpanded("lights"));
|
||||
ASSERT_EQ(frame.layout.visibleItemIndices.size(), 5u);
|
||||
EXPECT_EQ(frame.layout.visibleItemIndices[3], 3u);
|
||||
EXPECT_EQ(frame.layout.visibleItemIndices[4], 4u);
|
||||
}
|
||||
|
||||
TEST(UIEditorTreeViewInteractionTest, RightClickRowSelectsItemAndMarksSecondaryClick) {
|
||||
const auto items = BuildTreeItems();
|
||||
UISelectionModel selectionModel = {};
|
||||
UIExpansionModel expansionModel = {};
|
||||
expansionModel.Expand("scene");
|
||||
UIEditorTreeViewInteractionState state = {};
|
||||
|
||||
const auto initialFrame = UpdateUIEditorTreeViewInteraction(
|
||||
state,
|
||||
selectionModel,
|
||||
expansionModel,
|
||||
UIRect(0.0f, 0.0f, 320.0f, 240.0f),
|
||||
items,
|
||||
{});
|
||||
const UIPoint lightsCenter = RectCenter(initialFrame.layout.rowRects[2]);
|
||||
|
||||
const auto frame = UpdateUIEditorTreeViewInteraction(
|
||||
state,
|
||||
selectionModel,
|
||||
expansionModel,
|
||||
UIRect(0.0f, 0.0f, 320.0f, 240.0f),
|
||||
items,
|
||||
{
|
||||
MakePointerDown(lightsCenter.x, lightsCenter.y, UIPointerButton::Right),
|
||||
MakePointerUp(lightsCenter.x, lightsCenter.y, UIPointerButton::Right)
|
||||
});
|
||||
|
||||
EXPECT_TRUE(frame.result.consumed);
|
||||
EXPECT_TRUE(frame.result.secondaryClicked);
|
||||
EXPECT_TRUE(frame.result.selectionChanged);
|
||||
EXPECT_EQ(frame.result.selectedItemId, "lights");
|
||||
EXPECT_TRUE(selectionModel.IsSelected("lights"));
|
||||
EXPECT_TRUE(state.treeViewState.focused);
|
||||
}
|
||||
|
||||
TEST(UIEditorTreeViewInteractionTest, OutsideClickAndFocusLostClearFocusAndHover) {
|
||||
const auto items = BuildTreeItems();
|
||||
UISelectionModel selectionModel = {};
|
||||
UIExpansionModel expansionModel = {};
|
||||
expansionModel.Expand("scene");
|
||||
UIEditorTreeViewInteractionState state = {};
|
||||
state.treeViewState.focused = true;
|
||||
state.treeViewState.hoveredItemId = "camera";
|
||||
|
||||
auto frame = UpdateUIEditorTreeViewInteraction(
|
||||
state,
|
||||
selectionModel,
|
||||
expansionModel,
|
||||
UIRect(0.0f, 0.0f, 320.0f, 240.0f),
|
||||
items,
|
||||
{ MakePointerDown(400.0f, 260.0f), MakePointerUp(400.0f, 260.0f) });
|
||||
EXPECT_FALSE(state.treeViewState.focused);
|
||||
EXPECT_EQ(frame.result.hitTarget.kind, UIEditorTreeViewHitTargetKind::None);
|
||||
|
||||
frame = UpdateUIEditorTreeViewInteraction(
|
||||
state,
|
||||
selectionModel,
|
||||
expansionModel,
|
||||
UIRect(0.0f, 0.0f, 320.0f, 240.0f),
|
||||
items,
|
||||
{ MakePointerLeave(), MakeFocusLost() });
|
||||
EXPECT_FALSE(state.treeViewState.focused);
|
||||
EXPECT_TRUE(state.treeViewState.hoveredItemId.empty());
|
||||
EXPECT_FALSE(state.hasPointerPosition);
|
||||
}
|
||||
Reference in New Issue
Block a user