ComponentModeTests.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "ComponentModeTestDoubles.h"
  9. #include "ComponentModeTestFixture.h"
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. #include <AzCore/UnitTest/TestTypes.h>
  12. #include <AzFramework/Components/TransformComponent.h>
  13. #include <AzFramework/Entity/EntityContext.h>
  14. #include <AzTest/AzTest.h>
  15. #include <AzToolsFramework/API/EntityCompositionRequestBus.h>
  16. #include <AzToolsFramework/Application/ToolsApplication.h>
  17. #include <AzToolsFramework/ComponentMode/ComponentModeCollection.h>
  18. #include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
  19. #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
  20. #include <AzToolsFramework/ToolsComponents/EditorLockComponent.h>
  21. #include <AzToolsFramework/ToolsComponents/EditorPendingCompositionBus.h>
  22. #include <AzToolsFramework/ToolsComponents/EditorVisibilityComponent.h>
  23. #include <AzToolsFramework/ToolsComponents/TransformComponent.h>
  24. #include <AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx>
  25. #include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
  26. #include <AzToolsFramework/Viewport/ActionBus.h>
  27. #include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
  28. #include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
  29. #include <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
  30. #include <QApplication>
  31. namespace UnitTest
  32. {
  33. using namespace AzToolsFramework;
  34. using namespace AzToolsFramework::ComponentModeFramework;
  35. TEST_F(ComponentModeTestFixture, BeginEndComponentMode)
  36. {
  37. using ::testing::Eq;
  38. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  39. // Given
  40. QWidget rootWidget;
  41. ActionOverrideRequestBus::Event(GetEntityContextId(), &ActionOverrideRequests::SetupActionOverrideHandler, &rootWidget);
  42. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  43. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  44. // When
  45. ComponentModeSystemRequestBus::Broadcast(
  46. &ComponentModeSystemRequests::BeginComponentMode, AZStd::vector<EntityAndComponentModeBuilders>{});
  47. bool inComponentMode = false;
  48. ComponentModeSystemRequestBus::BroadcastResult(inComponentMode, &ComponentModeSystemRequests::InComponentMode);
  49. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  50. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  51. // Then
  52. EXPECT_TRUE(inComponentMode);
  53. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  54. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  55. // When
  56. ComponentModeSystemRequestBus::Broadcast(&ComponentModeSystemRequests::EndComponentMode);
  57. ComponentModeSystemRequestBus::BroadcastResult(inComponentMode, &ComponentModeSystemRequests::InComponentMode);
  58. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  59. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  60. // Then
  61. EXPECT_FALSE(inComponentMode);
  62. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  63. ActionOverrideRequestBus::Event(GetEntityContextId(), &ActionOverrideRequests::TeardownActionOverrideHandler);
  64. }
  65. TEST_F(ComponentModeTestFixture, TwoComponentsOnSingleEntityWithSameComponentModeBothBegin)
  66. {
  67. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  68. // Given
  69. // setup default editor interaction model
  70. AZ::Entity* entity = nullptr;
  71. AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity);
  72. entity->Deactivate();
  73. // add two placeholder Components (each with their own Component Mode)
  74. const AZ::Component* placeholder1 = entity->CreateComponent<PlaceholderEditorComponent>();
  75. const AZ::Component* placeholder2 = entity->CreateComponent<PlaceholderEditorComponent>();
  76. entity->Activate();
  77. // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate
  78. // connects to the ComponentModeDelegateRequestBus on the entity/component pair address)
  79. const AzToolsFramework::EntityIdList entityIds = { entityId };
  80. ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds);
  81. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  82. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  83. // When
  84. // move all selected components into ComponentMode
  85. // (mimic pressing the 'Edit' button to begin Component Mode)
  86. ComponentModeSystemRequestBus::Broadcast(
  87. &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo<PlaceholderEditorComponent>::Uuid());
  88. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  89. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  90. // Then
  91. bool firstComponentModeInstantiated = false;
  92. ComponentModeSystemRequestBus::BroadcastResult(
  93. firstComponentModeInstantiated, &ComponentModeSystemRequests::ComponentModeInstantiated,
  94. AZ::EntityComponentIdPair(entityId, placeholder1->GetId()));
  95. bool secondComponentModeInstantiated = false;
  96. ComponentModeSystemRequestBus::BroadcastResult(
  97. secondComponentModeInstantiated, &ComponentModeSystemRequests::ComponentModeInstantiated,
  98. AZ::EntityComponentIdPair(entityId, placeholder2->GetId()));
  99. EXPECT_TRUE(firstComponentModeInstantiated && secondComponentModeInstantiated);
  100. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  101. }
  102. TEST_F(ComponentModeTestFixture, OneComponentModeBeginsWithTwoComponentsOnSingleEntityEachWithDifferentComponentModes)
  103. {
  104. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  105. // Given
  106. // setup default editor interaction model
  107. AZ::Entity* entity = nullptr;
  108. AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity);
  109. entity->Deactivate();
  110. // add two placeholder Components (each with their own Component Mode)
  111. const AZ::Component* placeholder1 = entity->CreateComponent<PlaceholderEditorComponent>();
  112. const AZ::Component* placeholder2 = entity->CreateComponent<AnotherPlaceholderEditorComponent>();
  113. entity->Activate();
  114. // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate
  115. // connects to the ComponentModeDelegateRequestBus on the entity/component pair address)
  116. const AzToolsFramework::EntityIdList entityIds = { entityId };
  117. ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds);
  118. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  119. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  120. // When
  121. // move all selected components into ComponentMode
  122. // (mimic pressing the 'Edit' button to begin Component Mode)
  123. ComponentModeSystemRequestBus::Broadcast(
  124. &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo<PlaceholderEditorComponent>::Uuid());
  125. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  126. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  127. // Then
  128. bool firstComponentModeInstantiated = false;
  129. ComponentModeSystemRequestBus::BroadcastResult(
  130. firstComponentModeInstantiated, &ComponentModeSystemRequests::ComponentModeInstantiated,
  131. AZ::EntityComponentIdPair(entityId, placeholder1->GetId()));
  132. bool secondComponentModeInstantiated = true;
  133. ComponentModeSystemRequestBus::BroadcastResult(
  134. secondComponentModeInstantiated, &ComponentModeSystemRequests::ComponentModeInstantiated,
  135. AZ::EntityComponentIdPair(entityId, placeholder2->GetId()));
  136. EXPECT_TRUE(firstComponentModeInstantiated && !secondComponentModeInstantiated);
  137. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  138. }
  139. TEST_F(ComponentModeTestFixture, TwoComponentsOnSingleEntityWithSameComponentModeDoNotCycle)
  140. {
  141. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  142. // Given
  143. // setup default editor interaction model
  144. AZ::Entity* entity = nullptr;
  145. AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity);
  146. entity->Deactivate();
  147. // add two placeholder Components (each with their own Component Mode)
  148. const AZ::Component* placeholder1 = entity->CreateComponent<PlaceholderEditorComponent>();
  149. AZ_UNUSED(placeholder1);
  150. const AZ::Component* placeholder2 = entity->CreateComponent<PlaceholderEditorComponent>();
  151. AZ_UNUSED(placeholder2);
  152. entity->Activate();
  153. // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate
  154. // connects to the ComponentModeDelegateRequestBus on the entity/component pair address)
  155. const AzToolsFramework::EntityIdList entityIds = { entityId };
  156. ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds);
  157. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  158. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  159. // When
  160. // move all selected components into ComponentMode
  161. // (mimic pressing the 'Edit' button to begin Component Mode)
  162. ComponentModeSystemRequestBus::Broadcast(
  163. &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo<PlaceholderEditorComponent>::Uuid());
  164. bool nextModeCycled = true;
  165. ComponentModeSystemRequestBus::BroadcastResult(nextModeCycled, &ComponentModeSystemRequests::SelectNextActiveComponentMode);
  166. bool previousModeCycled = true;
  167. ComponentModeSystemRequestBus::BroadcastResult(previousModeCycled, &ComponentModeSystemRequests::SelectPreviousActiveComponentMode);
  168. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  169. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  170. // Then
  171. EXPECT_TRUE(!nextModeCycled && !previousModeCycled);
  172. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  173. }
  174. TEST_F(ComponentModeTestFixture, TwoComponentsOnSingleEntityWithSameComponentModeHasOnlyOneType)
  175. {
  176. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  177. // Given
  178. // setup default editor interaction model
  179. AZ::Entity* entity = nullptr;
  180. AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity);
  181. entity->Deactivate();
  182. // add two placeholder Components (each with their own Component Mode)
  183. const AZ::Component* placeholder1 = entity->CreateComponent<PlaceholderEditorComponent>();
  184. AZ_UNUSED(placeholder1);
  185. const AZ::Component* placeholder2 = entity->CreateComponent<PlaceholderEditorComponent>();
  186. AZ_UNUSED(placeholder2);
  187. entity->Activate();
  188. // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate
  189. // connects to the ComponentModeDelegateRequestBus on the entity/component pair address)
  190. const AzToolsFramework::EntityIdList entityIds = { entityId };
  191. ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds);
  192. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  193. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  194. // When
  195. // move all selected components into ComponentMode
  196. // (mimic pressing the 'Edit' button to begin Component Mode)
  197. ComponentModeSystemRequestBus::Broadcast(
  198. &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo<PlaceholderEditorComponent>::Uuid());
  199. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  200. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  201. // Then
  202. bool multipleComponentModeTypes = true;
  203. ComponentModeSystemRequestBus::BroadcastResult(multipleComponentModeTypes, &ComponentModeSystemRequests::HasMultipleComponentTypes);
  204. EXPECT_FALSE(multipleComponentModeTypes);
  205. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  206. }
  207. TEST_F(ComponentModeTestFixture, TwoComponentsOnSingleEntityWithDifferentComponentModeHasOnlyOneType)
  208. {
  209. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  210. // Given
  211. // setup default editor interaction model
  212. AZ::Entity* entity = nullptr;
  213. AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity);
  214. entity->Deactivate();
  215. // add two placeholder Components (each with their own Component Mode)
  216. const AZ::Component* placeholder1 = entity->CreateComponent<PlaceholderEditorComponent>();
  217. AZ_UNUSED(placeholder1);
  218. const AZ::Component* placeholder2 = entity->CreateComponent<AnotherPlaceholderEditorComponent>();
  219. AZ_UNUSED(placeholder2);
  220. entity->Activate();
  221. // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate
  222. // connects to the ComponentModeDelegateRequestBus on the entity/component pair address)
  223. const AzToolsFramework::EntityIdList entityIds = { entityId };
  224. ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds);
  225. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  226. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  227. // When
  228. // move all selected components into ComponentMode
  229. // (mimic pressing the 'Edit' button to begin Component Mode)
  230. ComponentModeSystemRequestBus::Broadcast(
  231. &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo<AnotherPlaceholderEditorComponent>::Uuid());
  232. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  233. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  234. // Then
  235. bool multipleComponentModeTypes = true;
  236. ComponentModeSystemRequestBus::BroadcastResult(multipleComponentModeTypes, &ComponentModeSystemRequests::HasMultipleComponentTypes);
  237. EXPECT_FALSE(multipleComponentModeTypes);
  238. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  239. }
  240. TEST_F(ComponentModeTestFixture, TwoComponentsOnSingleEntityWithDependentComponentModesHasTwoTypes)
  241. {
  242. using testing::Eq;
  243. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  244. // Given
  245. // setup default editor interaction model
  246. AZ::Entity* entity = nullptr;
  247. AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity);
  248. entity->Deactivate();
  249. // add two placeholder Components (each with their own Component Mode)
  250. const AZ::Component* placeholder1 = entity->CreateComponent<AnotherPlaceholderEditorComponent>();
  251. AZ_UNUSED(placeholder1);
  252. // DependentPlaceholderEditorComponent has a Component Mode dependent on AnotherPlaceholderEditorComponent
  253. const AZ::Component* placeholder2 = entity->CreateComponent<DependentPlaceholderEditorComponent>();
  254. AZ_UNUSED(placeholder2);
  255. entity->Activate();
  256. // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate
  257. // connects to the ComponentModeDelegateRequestBus on the entity/component pair address)
  258. const AzToolsFramework::EntityIdList entityIds = { entityId };
  259. ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds);
  260. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  261. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  262. // When
  263. // move all selected components into ComponentMode
  264. // (mimic pressing the 'Edit' button to begin Component Mode)
  265. ComponentModeSystemRequestBus::Broadcast(
  266. &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo<DependentPlaceholderEditorComponent>::Uuid());
  267. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  268. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  269. // Then
  270. bool multipleComponentModeTypes = false;
  271. ComponentModeSystemRequestBus::BroadcastResult(multipleComponentModeTypes, &ComponentModeSystemRequests::HasMultipleComponentTypes);
  272. bool secondComponentModeInstantiated = false;
  273. ComponentModeSystemRequestBus::BroadcastResult(
  274. secondComponentModeInstantiated, &ComponentModeSystemRequests::ComponentModeInstantiated,
  275. AZ::EntityComponentIdPair(entityId, placeholder2->GetId()));
  276. AZ::Uuid activeComponentType = AZ::Uuid::CreateNull();
  277. ComponentModeSystemRequestBus::BroadcastResult(activeComponentType, &ComponentModeSystemRequests::ActiveComponentMode);
  278. EXPECT_TRUE(multipleComponentModeTypes);
  279. EXPECT_TRUE(secondComponentModeInstantiated);
  280. EXPECT_THAT(activeComponentType, Eq(AZ::AzTypeInfo<DependentPlaceholderEditorComponent>::Uuid()));
  281. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  282. }
  283. TEST_F(ComponentModeTestFixture, TwoComponentsOnSingleEntityWithSameComponentModeBothTriggerSameAction)
  284. {
  285. using testing::Eq;
  286. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  287. // Given
  288. AZ::Entity* entity = nullptr;
  289. AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity);
  290. entity->Deactivate();
  291. // add two placeholder Components (each with their own Component Mode)
  292. const AZ::Component* placeholder1 = entity->CreateComponent<PlaceholderEditorComponent>();
  293. const AZ::Component* placeholder2 = entity->CreateComponent<PlaceholderEditorComponent>();
  294. entity->Activate();
  295. // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate
  296. // connects to the ComponentModeDelegateRequestBus on the entity/component pair address)
  297. AzToolsFramework::SelectEntity(entityId);
  298. // move all selected components into ComponentMode
  299. // (mimic pressing the 'Edit' button to begin Component Mode)
  300. EnterComponentMode<PlaceholderEditorComponent>();
  301. // Component Modes are now instantiated
  302. // create a simple signal checker type which implements the ComponentModeActionSignalNotificationBus
  303. const int checkerBusId = 1234;
  304. ComponentModeActionSignalNotificationChecker checker(checkerBusId);
  305. // when a shortcut action happens, we want to send a message to the checker bus
  306. // internally PlaceHolderComponentMode sets up an action to send an event to
  307. // ComponentModeActionSignalNotifications::OnActionTriggered - we make sure each
  308. // Component Mode is will sent the notification to the correct address.
  309. ComponentModeActionSignalRequestBus::Event(
  310. AZ::EntityComponentIdPair(entityId, placeholder1->GetId()),
  311. &ComponentModeActionSignalRequests::SetComponentModeActionNotificationBusToNotify, checkerBusId);
  312. ComponentModeActionSignalRequestBus::Event(
  313. AZ::EntityComponentIdPair(entityId, placeholder2->GetId()),
  314. &ComponentModeActionSignalRequests::SetComponentModeActionNotificationBusToNotify, checkerBusId);
  315. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  316. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  317. // When
  318. // trigger the shortcut for this Component Mode
  319. QTest::keyPress(&m_editorActions.m_componentModeWidget, Qt::Key_Space);
  320. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  321. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  322. // Then
  323. // ensure the checker count is what we expect (both Component Modes will notify the
  324. // ComponentModeActionSignalNotificationChecker connected at the address specified)
  325. EXPECT_THAT(checker.GetCount(), Eq(2));
  326. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  327. }
  328. TEST_F(ComponentModeTestFixture, ShouldIgnoreMouseEventWhenOverridenByComponentMode)
  329. {
  330. using OverrideMouseInteractionComponent = TestComponentModeComponent<OverrideMouseInteractionComponentMode>;
  331. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  332. // Given
  333. // Setup default editor interaction model.
  334. AZ::Entity* entity = nullptr;
  335. AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity);
  336. entity->Deactivate();
  337. // Add placeholder component which implements component mode.
  338. entity->CreateComponent<OverrideMouseInteractionComponent>();
  339. entity->Activate();
  340. // Mimic selecting the entity in the viewport (after selection the ComponentModeDelegate
  341. // connects to the ComponentModeDelegateRequestBus on the entity/component pair address)
  342. AzToolsFramework::SelectEntity(entityId);
  343. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  344. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  345. // When
  346. // Move all selected components into ComponentMode
  347. // (mimic pressing the 'Edit' button to begin Component Mode)
  348. EnterComponentMode<OverrideMouseInteractionComponent>();
  349. ViewportInteraction::MouseInteractionEvent interactionEvent;
  350. interactionEvent.m_mouseEvent = ViewportInteraction::MouseEvent::Move;
  351. // Simulate a mouse event
  352. using MouseInteractionResult = AzToolsFramework::ViewportInteraction::MouseInteractionResult;
  353. MouseInteractionResult handled = MouseInteractionResult::None;
  354. EditorInteractionSystemViewportSelectionRequestBus::BroadcastResult(
  355. handled, &EditorInteractionSystemViewportSelectionRequestBus::Events::InternalHandleAllMouseInteractions, interactionEvent);
  356. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  357. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  358. // Then
  359. // Check it was handled by the component mode.
  360. EXPECT_EQ(handled, MouseInteractionResult::Viewport);
  361. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  362. }
  363. // Test version of EntityPropertyEditor to detect/ensure certain functions were called
  364. class TestEntityPropertyEditor : public AzToolsFramework::EntityPropertyEditor
  365. {
  366. public:
  367. AZ_CLASS_ALLOCATOR(TestEntityPropertyEditor, AZ::SystemAllocator)
  368. void InvalidatePropertyDisplay(PropertyModificationRefreshLevel level) override;
  369. bool m_invalidatePropertyDisplayCalled = false;
  370. };
  371. void TestEntityPropertyEditor::InvalidatePropertyDisplay([[maybe_unused]] PropertyModificationRefreshLevel level)
  372. {
  373. m_invalidatePropertyDisplayCalled = true;
  374. }
  375. // Simple fixture to encapsulate a TestEntityPropertyEditor
  376. class ComponentModePinnedSelectionFixture : public ToolsApplicationFixture<>
  377. {
  378. public:
  379. void SetUpEditorFixtureImpl() override
  380. {
  381. m_testEntityPropertyEditor = AZStd::make_unique<TestEntityPropertyEditor>();
  382. }
  383. void TearDownEditorFixtureImpl() override
  384. {
  385. m_testEntityPropertyEditor.reset();
  386. }
  387. AZStd::unique_ptr<TestEntityPropertyEditor> m_testEntityPropertyEditor;
  388. };
  389. TEST_F(ComponentModePinnedSelectionFixture, CannotEnterComponentModeWhenEntityIsPinnedButNotSelected)
  390. {
  391. using PlaceHolderComponent = TestComponentModeComponent<PlaceHolderComponentMode>;
  392. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  393. // Given
  394. AZ::Entity* entity = nullptr;
  395. AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity);
  396. entity->Deactivate();
  397. // Add placeholder component which implements component mode.
  398. entity->CreateComponent<PlaceHolderComponent>();
  399. AZ_TEST_START_TRACE_SUPPRESSION;
  400. entity->Activate();
  401. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  402. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  403. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  404. // When
  405. // select entity
  406. const auto selectedEntities = AzToolsFramework::EntityIdList{ entityId };
  407. SelectEntities(selectedEntities);
  408. // pin entity
  409. AzToolsFramework::EntityIdSet selectedSet(selectedEntities.begin(), selectedEntities.end());
  410. m_testEntityPropertyEditor->SetOverrideEntityIds(selectedSet);
  411. // deselect entity
  412. SelectEntities(AzToolsFramework::EntityIdList{});
  413. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  414. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  415. // Then
  416. EXPECT_TRUE(m_testEntityPropertyEditor->IsLockedToSpecificEntities());
  417. EXPECT_TRUE(m_testEntityPropertyEditor->m_invalidatePropertyDisplayCalled);
  418. bool couldBeginComponentMode = AzToolsFramework::ComponentModeFramework::CouldBeginComponentModeWithEntity(entityId);
  419. EXPECT_FALSE(couldBeginComponentMode);
  420. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  421. }
  422. TEST_F(ComponentModeTestFixture, CannotEnterComponentModeWhenThereArePendingComponents)
  423. {
  424. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  425. // Given
  426. AZ::Entity* entity = nullptr;
  427. AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity);
  428. entity->Deactivate();
  429. AzToolsFramework::EntityCompositionRequestBus::Broadcast(
  430. &AzToolsFramework::EntityCompositionRequestBus::Events::AddComponentsToEntities, AzToolsFramework::EntityIdList{ entityId },
  431. AZ::ComponentTypeList{ AZ::AzTypeInfo<AnotherPlaceholderEditorComponent>::Uuid() });
  432. AzToolsFramework::EntityCompositionRequestBus::Broadcast(
  433. &AzToolsFramework::EntityCompositionRequestBus::Events::AddComponentsToEntities, AzToolsFramework::EntityIdList{ entityId },
  434. AZ::ComponentTypeList{ AZ::AzTypeInfo<IncompatiblePlaceholderEditorComponent>::Uuid() });
  435. entity->Activate();
  436. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  437. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  438. // When
  439. SelectEntities(AzToolsFramework::EntityIdList{ entityId });
  440. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  441. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  442. // Then
  443. AZ::Entity::ComponentArrayType pendingComponents;
  444. AzToolsFramework::EditorPendingCompositionRequestBus::Event(
  445. entityId, &AzToolsFramework::EditorPendingCompositionRequestBus::Events::GetPendingComponents, pendingComponents);
  446. // ensure we do have pending components
  447. EXPECT_EQ(pendingComponents.size(), 1);
  448. // cannot enter Component Mode with pending components
  449. EXPECT_FALSE(AzToolsFramework::ComponentModeFramework::CouldBeginComponentModeWithEntity(entityId));
  450. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  451. }
  452. } // namespace UnitTest