/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace EMotionFX { class CanAddSimulatedObjectFixture : public UIFixture { public: void TearDown() override { QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); UIFixture::TearDown(); } void RecursiveGetAllChildren(QTreeView* treeView, const QModelIndex& index, QModelIndexList& outIndicies) { outIndicies.push_back(index); for (int i = 0; i < treeView->model()->rowCount(index); ++i) { RecursiveGetAllChildren(treeView, treeView->model()->index(i, 0, index), outIndicies); } } void CreateSimulateObject(const char* objectName) { // Select the newly created actor { AZStd::string result; EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand("Select -actorID 0", result)) << result.c_str(); } // Change the Editor mode to Simulated Objects EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects"); // Find the Simulated Object Manager and its button m_simulatedObjectWidget = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SimulatedObjectWidget::CLASS_ID)); ASSERT_TRUE(m_simulatedObjectWidget) << "Simulated Object plugin not found!"; QPushButton* addSimulatedObjectButton = m_simulatedObjectWidget->GetDockWidget()->findChild("addSimulatedObjectButton"); // Send the left button click directly to the button QTest::mouseClick(addSimulatedObjectButton, Qt::LeftButton); // In the Input Dialog set the name of the object and close the dialog EMStudio::InputDialogValidatable* inputDialog = qobject_cast(FindTopLevelWidget("EMFX.SimulatedObjectActionManager.SimulatedObjectDialog")); ASSERT_NE(inputDialog, nullptr) << "Cannot find input dialog."; inputDialog->SetText(objectName); inputDialog->accept(); // There is one and only one simulated objects ASSERT_EQ(m_actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 1); // Check it has the correct name EXPECT_STREQ(m_actor->GetSimulatedObjectSetup()->GetSimulatedObject(0)->GetName().c_str(), objectName); } void AddCapsuleColliderToJointIndex(int index) { m_skeletonTreeView->selectionModel()->clearSelection(); // Find the indexed joint in the TreeView and select it SelectIndexes(m_indexList, m_skeletonTreeView, index, index); // Open the Right Click Context Menu const QRect rect = m_skeletonTreeView->visualRect(m_indexList[index-1]); EXPECT_TRUE(rect.isValid()); BringUpContextMenu(m_skeletonTreeView, rect); QMenu* contextMenu = m_skeletonOutliner->GetDockWidget()->findChild("contextMenu"); // Trace down the sub Menus to Add Collider and select it QAction* simulatedObjectColliderAction = GetNamedAction(m_skeletonOutliner->GetDockWidget(), "Simulated object collider"); ASSERT_TRUE(simulatedObjectColliderAction); QMenu* simulatedObjectColliderMenu = simulatedObjectColliderAction->menu(); const QList simulatedObjecColliderActions = simulatedObjectColliderMenu->actions(); auto addSelectedAddColliderActionItr = AZStd::find_if(simulatedObjecColliderActions.begin(), simulatedObjecColliderActions.end(), [](const QAction* action) { return action->text() == "Add collider"; }); ASSERT_NE(addSelectedAddColliderActionItr, simulatedObjecColliderActions.end()); QMenu* addSelectedColliderMenu = (*addSelectedAddColliderActionItr)->menu(); const QList addSelectedColliderMenuActions = addSelectedColliderMenu->actions(); auto addCapsuleColliderAction = AZStd::find_if(addSelectedColliderMenuActions.begin(), addSelectedColliderMenuActions.end(), [](const QAction* action) { return action->text() == "Add capsule"; }); ASSERT_NE(addCapsuleColliderAction, addSelectedColliderMenuActions.end()); size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); (*addCapsuleColliderAction)->trigger(); // Delete the context menu, otherwise there it will still be around during this frame as the Qt event loop has not been run. delete contextMenu; const size_t numCapsuleCollidersAfterAdd = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); ASSERT_EQ(numCapsuleCollidersAfterAdd, numCapsuleColliders + 1); m_skeletonTreeView->selectionModel()->clearSelection(); } protected: AutoRegisteredActor m_actor; EMotionFX::SimulatedObjectWidget* m_simulatedObjectWidget = nullptr; EMotionFX::SkeletonOutlinerPlugin* m_skeletonOutliner = nullptr; ReselectingTreeView* m_skeletonTreeView = nullptr; const QAbstractItemModel* m_skeletonModel; QModelIndexList m_indexList; }; TEST_F(CanAddSimulatedObjectFixture, CanAddSimulatedObject) { RecordProperty("test_case_id", "C13048820"); m_actor = ActorFactory::CreateAndInit(1, "CanAddSimulatedObjectActor"); CreateSimulateObject("New simulated object"); } TEST_F(UIFixture, CanAddSimulatedObjectWithJoints) { RecordProperty("test_case_id", "C13048818"); AutoRegisteredActor actor = ActorFactory::CreateAndInit(2, "CanAddSimulatedObjectWithJointsActor"); ActorInstance* actorInstance = ActorInstance::Create(actor.get()); EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects"); { AZStd::string result; EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(AZStd::string{"Select -actorInstanceID "} + AZStd::to_string(actorInstance->GetID()), result)) << result.c_str(); } auto simulatedObjectWidget = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SimulatedObjectWidget::CLASS_ID)); ASSERT_TRUE(simulatedObjectWidget) << "Simulated Object plugin not found!"; auto skeletonOutliner = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SkeletonOutlinerPlugin::CLASS_ID)); QTreeView* treeView = skeletonOutliner->GetDockWidget()->findChild("EMFX.SkeletonOutlinerPlugin.SkeletonOutlinerTreeView"); const QAbstractItemModel* model = treeView->model(); const QModelIndex rootJointIndex = model->index(0, 0); ASSERT_TRUE(rootJointIndex.isValid()) << "Unable to find a model index for the root joint of the actor"; treeView->selectionModel()->select(rootJointIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows); treeView->scrollTo(rootJointIndex); BringUpContextMenu(treeView, treeView->visualRect(rootJointIndex)); QMenu* contextMenu = skeletonOutliner->GetDockWidget()->findChild("EMFX.SkeletonOutlinerPlugin.ContextMenu"); EXPECT_TRUE(contextMenu); QAction* simulatedObjectAction; EXPECT_TRUE(UIFixture::GetActionFromContextMenu(simulatedObjectAction, contextMenu, "Simulated object")); QMenu* simulatedObjectMenu = simulatedObjectAction->menu(); EXPECT_TRUE(simulatedObjectMenu); QAction* addSelectedJointAction; EXPECT_TRUE(UIFixture::GetActionFromContextMenu(addSelectedJointAction, simulatedObjectMenu, "Add selected joint")); QMenu* addSelectedJointMenu = addSelectedJointAction->menu(); EXPECT_TRUE(addSelectedJointMenu); QAction* newSimulatedObjectAction; EXPECT_TRUE(UIFixture::GetActionFromContextMenu(newSimulatedObjectAction, addSelectedJointMenu, "")); newSimulatedObjectAction->trigger(); EMStudio::InputDialogValidatable* inputDialog = qobject_cast(FindTopLevelWidget("EMFX.SimulatedObjectActionManager.SimulatedObjectDialog")); ASSERT_NE(inputDialog, nullptr) << "Cannot find input dialog."; inputDialog->SetText("New simulated object"); inputDialog->accept(); ASSERT_EQ(actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 1); const auto simulatedObject = actor->GetSimulatedObjectSetup()->GetSimulatedObject(0); EXPECT_STREQ(simulatedObject->GetName().c_str(), "New simulated object"); EXPECT_EQ(simulatedObject->GetNumSimulatedRootJoints(), 1); EXPECT_EQ(simulatedObject->GetNumSimulatedJoints(), 1); EXPECT_STREQ(actor->GetSkeleton()->GetNode(simulatedObject->GetSimulatedJoint(0)->GetSkeletonJointIndex())->GetName(), "rootJoint"); EXPECT_STREQ(actor->GetSkeleton()->GetNode(simulatedObject->GetSimulatedRootJoint(0)->GetSkeletonJointIndex())->GetName(), "rootJoint"); QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); actorInstance->Destroy(); } TEST_F(CanAddSimulatedObjectFixture, CanAddSimulatedObjectWithJointsAndName) { RecordProperty("test_case_id", "C13048820a"); m_actor = ActorFactory::CreateAndInit(5, "CanAddSimulatedObjectActor"); CreateSimulateObject("sim1"); // Get the Skeleton Outliner and find the model relating to its treeview auto skeletonOutliner = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SkeletonOutlinerPlugin::CLASS_ID)); QTreeView* treeView = skeletonOutliner->GetDockWidget()->findChild("EMFX.SkeletonOutlinerPlugin.SkeletonOutlinerTreeView"); const QAbstractItemModel* model = treeView->model(); // Find the 3rd joint in the TreeView and select it const QModelIndex jointIndex = model->index(0, 3); ASSERT_TRUE(jointIndex.isValid()) << "Unable to find a model index for the root joint of the actor"; treeView->selectionModel()->select(jointIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows); treeView->scrollTo(jointIndex); // Open the Right Click Context Menu const QRect rect = treeView->visualRect(jointIndex); EXPECT_TRUE(rect.isValid()); BringUpContextMenu(treeView, rect); // Trace down the sub Menus to and select it QMenu* contextMenu = skeletonOutliner->GetDockWidget()->findChild("EMFX.SkeletonOutlinerPlugin.ContextMenu"); EXPECT_TRUE(contextMenu); QAction* simulatedObjectAction; EXPECT_TRUE(UIFixture::GetActionFromContextMenu(simulatedObjectAction, contextMenu, "Simulated object")); QMenu* simulatedObjectMenu = simulatedObjectAction->menu(); EXPECT_TRUE(simulatedObjectMenu); QAction* addSelectedJointAction; EXPECT_TRUE(UIFixture::GetActionFromContextMenu(addSelectedJointAction, simulatedObjectMenu, "Add selected joint")); QMenu* addSelectedJointMenu = addSelectedJointAction->menu(); EXPECT_TRUE(addSelectedJointMenu); QAction* newSimulatedObjectAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(newSimulatedObjectAction, addSelectedJointMenu, "")); newSimulatedObjectAction->trigger(); // Set the name in the Dialog Box and test it. EMStudio::InputDialogValidatable* inputDialog = qobject_cast(FindTopLevelWidget("EMFX.SimulatedObjectActionManager.SimulatedObjectDialog")); ASSERT_NE(inputDialog, nullptr) << "Cannot find input dialog."; inputDialog->SetText("sim2"); inputDialog->accept(); ASSERT_EQ(m_actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 2); const auto simulatedObject = m_actor->GetSimulatedObjectSetup()->GetSimulatedObject(1); EXPECT_STREQ(simulatedObject->GetName().c_str(), "sim2"); } TEST_F(CanAddSimulatedObjectFixture, CanAddColliderToSimulatedObject) { RecordProperty("test_case_id", "C13048816"); m_actor = ActorFactory::CreateAndInit(5, "CanAddSimulatedObjectActor"); CreateSimulateObject("sim1"); // Get the Skeleton Outliner and find the model relating to its treeview auto skeletonOutliner = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SkeletonOutlinerPlugin::CLASS_ID)); QTreeView* treeView = skeletonOutliner->GetDockWidget()->findChild("EMFX.SkeletonOutlinerPlugin.SkeletonOutlinerTreeView"); const QAbstractItemModel* model = treeView->model(); // Find the 3rd joint in the TreeView and select it const QModelIndex jointIndex = model->index(0, 3); ASSERT_TRUE(jointIndex.isValid()) << "Unable to find a model index for the root joint of the actor"; treeView->selectionModel()->select(jointIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows); treeView->scrollTo(jointIndex); // Open the Right Click Context Menu const QRect rect = treeView->visualRect(jointIndex); EXPECT_TRUE(rect.isValid()); BringUpContextMenu(treeView, rect); // Trace down the sub Menus to Add Collider and select it QMenu* contextMenu = skeletonOutliner->GetDockWidget()->findChild("EMFX.SkeletonOutlinerPlugin.ContextMenu"); EXPECT_TRUE(contextMenu); QAction* simulatedObjectColliderAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(simulatedObjectColliderAction, contextMenu, "Simulated object collider")); QMenu* simulatedObjectColliderMenu = simulatedObjectColliderAction->menu(); EXPECT_TRUE(simulatedObjectColliderMenu); QAction* addSelectedAddColliderAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addSelectedAddColliderAction, simulatedObjectColliderMenu, "Add collider")); QMenu* addSelectedColliderMenu = addSelectedAddColliderAction->menu(); QAction* addCapsuleColliderAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addCapsuleColliderAction, addSelectedColliderMenu, "Add capsule")); size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); EXPECT_EQ(numCapsuleColliders, 0); addCapsuleColliderAction->trigger(); // Check that a collider has been added. size_t numCollidersAfterAddCapsule = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); ASSERT_EQ(numCollidersAfterAddCapsule, numCapsuleColliders + 1) << "Capsule collider not added."; QAction* addSphereColliderAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addSphereColliderAction, addSelectedColliderMenu, "Add sphere")); const size_t numSphereColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); EXPECT_EQ(numSphereColliders, 0); addSphereColliderAction->trigger(); // Check that a second collider has been added. const size_t numCollidersAfterAddSphere = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); ASSERT_EQ(numCollidersAfterAddSphere, numSphereColliders + 1) << "Sphere collider not added."; } TEST_F(CanAddSimulatedObjectFixture, CanRemoveSimulatedObject) { RecordProperty("test_case_id", "C13048821"); m_actor = ActorFactory::CreateAndInit(1, "CanRemoveSimulatedObjectActor"); CreateSimulateObject("TestObject1"); // Get the Simulated Object and find the model relating to its treeview EMotionFX::SimulatedObjectWidget* simulatedObjectWidget = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SimulatedObjectWidget::CLASS_ID)); ASSERT_TRUE(simulatedObjectWidget); QTreeView* treeView = simulatedObjectWidget->GetDockWidget()->findChild("EMFX.SimulatedObjectWidget.TreeView"); ASSERT_TRUE(treeView); const SimulatedObjectModel* model = reinterpret_cast(treeView->model()); const QModelIndex index = model->index(0, 0); treeView->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows); treeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select | QItemSelectionModel::Rows); treeView->scrollTo(index); BringUpContextMenu(treeView, treeView->visualRect(index)); QMenu* contextMenu = simulatedObjectWidget->GetDockWidget()->findChild("EMFX.SimulatedObjectWidget.ContextMenu"); EXPECT_TRUE(contextMenu); QAction* removeObjectAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(removeObjectAction, contextMenu, "Remove object")); removeObjectAction->trigger(); ASSERT_EQ(m_actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 0); } TEST_F(CanAddSimulatedObjectFixture, CanAddColliderToSimulatedObjectFromInspector) { RecordProperty("test_case_id", "C20385259"); m_actor = ActorFactory::CreateAndInit(5, "CanAddSimulatedObjectActor"); CreateSimulateObject("sim1"); // Get the Skeleton Outliner and find the model relating to its treeview auto skeletonOutliner = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SkeletonOutlinerPlugin::CLASS_ID)); ASSERT_TRUE(skeletonOutliner); QTreeView* treeView = skeletonOutliner->GetDockWidget()->findChild("EMFX.SkeletonOutlinerPlugin.SkeletonOutlinerTreeView"); ASSERT_TRUE(treeView); const QAbstractItemModel* model = treeView->model(); QModelIndexList indexList; RecursiveGetAllChildren(treeView, model->index(0, 0), indexList); SelectIndexes(indexList, treeView, 3, 3); QDockWidget* simulatedObjectInspectorDock = EMStudio::GetMainWindow()->findChild("EMFX.SimulatedObjectWidget.SimulatedObjectInspectorDock"); ASSERT_TRUE(simulatedObjectInspectorDock); QPushButton* addColliderButton = simulatedObjectInspectorDock->findChild("EMFX.SimulatedObjectColliderWidget.AddColliderButton"); ASSERT_TRUE(addColliderButton); // Send the left button click directly to the button QTest::mouseClick(addColliderButton, Qt::LeftButton); const size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); EXPECT_EQ(numCapsuleColliders, 0); const size_t numSphereColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); EXPECT_EQ(numSphereColliders, 0); QMenu* contextMenu = addColliderButton->findChild("EMFX.AddColliderButton.ContextMenu"); EXPECT_TRUE(contextMenu); QAction* addCapsuleAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addCapsuleAction, contextMenu, "Add capsule")); addCapsuleAction->trigger(); const size_t numCollidersAfterAddCapsule = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); ASSERT_EQ(numCollidersAfterAddCapsule, numCapsuleColliders + 1) << "Capsule collider not added."; QAction* addSphereAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addSphereAction, contextMenu, "Add sphere")); addSphereAction->trigger(); const size_t numCollidersAfterAddSphere = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); ASSERT_EQ(numCollidersAfterAddSphere, numSphereColliders + 1) << "Sphere collider not added."; } TEST_F(CanAddSimulatedObjectFixture, CanAddMultipleJointsToSimulatedObject) { RecordProperty("test_case_id", "C13048818"); m_actor = ActorFactory::CreateAndInit(7, "CanAddSimulatedObjectActor"); CreateSimulateObject("ANY"); // Get the Skeleton Outliner and find the model relating to its treeview auto skeletonOutliner = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SkeletonOutlinerPlugin::CLASS_ID)); ASSERT_TRUE(skeletonOutliner) << "Can't find SkeletonOutlinerPlugin"; QTreeView* treeView = skeletonOutliner->GetDockWidget()->findChild("EMFX.SkeletonOutlinerPlugin.SkeletonOutlinerTreeView"); ASSERT_TRUE(treeView) << "Skeleton Treeview not found"; const QAbstractItemModel* model = treeView->model(); QModelIndexList indexList; RecursiveGetAllChildren(treeView, model->index(0, 0), indexList); SelectIndexes(indexList, treeView, 3, 5); // Open the Right Click Context Menu const QRect rect = treeView->visualRect(indexList[4]); EXPECT_TRUE(rect.isValid()); BringUpContextMenu(treeView, rect); // Trace down the sub Menus to and select it QMenu* contextMenu = skeletonOutliner->GetDockWidget()->findChild("EMFX.SkeletonOutlinerPlugin.ContextMenu"); EXPECT_TRUE(contextMenu) << "Context Menu not found"; QAction* simulatedObjectAction; EXPECT_TRUE(UIFixture::GetActionFromContextMenu(simulatedObjectAction, contextMenu, "Simulated object")); QMenu* simulatedObjectMenu = simulatedObjectAction->menu(); EXPECT_TRUE(simulatedObjectMenu) << "Simulated Object Menu not found"; QAction* addSelectedJointAction; EXPECT_TRUE(UIFixture::GetActionFromContextMenu(addSelectedJointAction, simulatedObjectMenu, "Add selected joints")); QMenu* addSelectedJointMenu = addSelectedJointAction->menu(); EXPECT_TRUE(addSelectedJointMenu) << "Add selected joints menu not found"; QAction* newSimulatedObjectAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(newSimulatedObjectAction, addSelectedJointMenu, "ANY")) << "Can't find named simulated object in menu"; newSimulatedObjectAction->trigger(); const EMotionFX::SimulatedObject* simulatedObject = m_actor->GetSimulatedObjectSetup()->GetSimulatedObject(0); EXPECT_EQ(simulatedObject->GetNumSimulatedRootJoints(), 1); EXPECT_EQ(simulatedObject->GetNumSimulatedJoints(), 3); } TEST_F(CanAddSimulatedObjectFixture, CanRemoveColliderFromSimulatedObject) { RecordProperty("test_case_id", "C13048817"); m_actor = ActorFactory::CreateAndInit(5, "CanAddSimulatedObjectActor"); EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects"); QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); CreateSimulateObject("sim1"); m_skeletonOutliner = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SkeletonOutlinerPlugin::CLASS_ID)); m_skeletonTreeView = m_skeletonOutliner->GetDockWidget()->findChild("EMFX.SkeletonOutlinerPlugin.SkeletonOutlinerTreeView"); m_skeletonModel = m_skeletonTreeView->model(); m_indexList.clear(); m_skeletonTreeView->RecursiveGetAllChildren(m_skeletonTreeView->model()->index(0, 0), m_indexList); // Add colliders to two joints. AddCapsuleColliderToJointIndex(3); AddCapsuleColliderToJointIndex(4); const size_t numCollidersAfterAdd = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider); EXPECT_EQ(numCollidersAfterAdd, 2); m_indexList.clear(); m_skeletonTreeView->RecursiveGetAllChildren(m_skeletonTreeView->model()->index(0, 0), m_indexList); // Reselect joint 3 and pop up the context menu for it. m_skeletonTreeView->selectionModel()->clearSelection(); SelectIndexes(m_indexList, m_skeletonTreeView, 3, 3); // Open the Right Click Context Menu const QRect rect = m_skeletonTreeView->visualRect(m_indexList[2]); EXPECT_TRUE(rect.isValid()); BringUpContextMenu(m_skeletonTreeView, rect); const QList contextMenus = m_skeletonOutliner->GetDockWidget()->findChildren("EMFX.SimulatedObjectWidget.SimulatedObjectColliderMenu"); EXPECT_NE(contextMenus.size(), 0) << "Unable to find Skeketon Outliner context menu."; // There will be several existing menus, as the Qt event loop has not yet been run, so we need to find the latest and use that. QMenu* contextMenu = *(contextMenus.end() - 1); QAction* removeAction = contextMenu->findChild("EMFX.SimulatedObjectWidget.RemoveCollidersAction"); ASSERT_TRUE(removeAction); removeAction->trigger(); // Check that one of the colliders is now gone. const size_t numCollidersAfterFirstRemove = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider); ASSERT_EQ(numCollidersAfterFirstRemove, numCollidersAfterAdd - 1) << "RemoveCollider action in Simulated Object Inspector failed."; // Now do the same thing using the Simulated Object Inspector context menu. const SimulatedObjectColliderWidget* simulatedObjectColliderWidget = GetSimulatedObjectColliderWidget(); ASSERT_TRUE(simulatedObjectColliderWidget) << "SimulatedObjectColliderWidget not found."; // Select the second collider that was made earlier. m_skeletonTreeView->selectionModel()->clearSelection(); SelectIndexes(m_indexList, m_skeletonTreeView, 4, 4); const ColliderContainerWidget* colliderContainerWidget = simulatedObjectColliderWidget->findChild< ColliderContainerWidget*>(); ASSERT_TRUE(colliderContainerWidget) << "ColliderContainerWidget not found."; // Get the collider widget card from the container. const ColliderWidget* colliderWidget = colliderContainerWidget->findChild(); ASSERT_TRUE(colliderWidget) << "ColliderWidget not found."; const AzQtComponents::CardHeader* cardHeader = colliderWidget->findChild(); ASSERT_TRUE(cardHeader) << "ColliderWidget CardHeader not found."; const QFrame* frame = cardHeader->findChild("Background"); ASSERT_TRUE(frame) << "ColliderWidget CardHeader Background Frame not found."; QPushButton* contextMenubutton = frame->findChild< QPushButton*>("ContextMenu"); ASSERT_TRUE(contextMenubutton) << "ColliderWidget ContextMenu not found."; // Pop up the context menu. QTest::mouseClick(contextMenubutton, Qt::LeftButton); // Find the delete collider button and press it. const QMenu* collilderWidgetContextMenu = colliderWidget->findChild("EMFX.ColliderContainerWidget.ContextMenu"); QAction* delAction = collilderWidgetContextMenu->findChild("EMFX.ColliderContainerWidget.DeleteColliderAction"); delAction->trigger(); // Check that we have the number of colliders we started we expect. const size_t numCollidersAfterSecondRemove = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider); ASSERT_EQ(numCollidersAfterSecondRemove, numCollidersAfterAdd - 2); } } // namespace EMotionFX