123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AzCore/Component/ComponentApplicationBus.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzCore/std/smart_ptr/make_shared.h>
- #include <AzFramework/Physics/ShapeConfiguration.h>
- #include <AzFramework/Entity/EntityDebugDisplayBus.h>
- #include <AzQtComponents/Components/Widgets/CardHeader.h>
- #include <EMotionFX/CommandSystem/Source/ColliderCommands.h>
- #include <EMotionFX/CommandSystem/Source/SimulatedObjectCommands.h>
- #include <EMotionFX/Source/Actor.h>
- #include <EMotionFX/Source/ActorInstance.h>
- #include <EMotionFX/Source/ActorManager.h>
- #include <EMotionFX/Source/Node.h>
- #include <EMotionFX/Source/TransformData.h>
- #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
- #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/ViewportPluginBus.h>
- #include <Editor/ColliderContainerWidget.h>
- #include <Editor/ColliderHelpers.h>
- #include <Editor/ObjectEditor.h>
- #include <Editor/Plugins/Ragdoll/PhysicsSetupManipulatorBus.h>
- #include <Editor/SkeletonModel.h>
- #include <MCore/Source/AzCoreConversions.h>
- #include <MysticQt/Source/MysticQtManager.h>
- #include <QClipboard>
- #include <QContextMenuEvent>
- #include <QEvent>
- #include <QGuiApplication>
- #include <QMenu>
- #include <QMimeData>
- #include <QPushButton>
- #include <QVBoxLayout>
- #include <Qt>
- namespace EMotionFX
- {
- ColliderPropertyNotify::ColliderPropertyNotify(ColliderWidget* colliderWidget)
- : m_colliderWidget(colliderWidget)
- {
- }
- void ColliderPropertyNotify::BeforePropertyModified(AzToolsFramework::InstanceDataNode* node)
- {
- if (!m_commandGroup.IsEmpty())
- {
- return;
- }
- const AzToolsFramework::InstanceDataNode* parentDataNode = node->GetParent();
- if (!parentDataNode)
- {
- return;
- }
- const AZ::SerializeContext* serializeContext = parentDataNode->GetSerializeContext();
- const AZ::SerializeContext::ClassData* classData = parentDataNode->GetClassMetadata();
- const AZ::SerializeContext::ClassElement* elementData = node->GetElementMetadata();
- const Actor* actor = m_colliderWidget->GetActor();
- const Node* joint = m_colliderWidget->GetJoint();
- if (!actor || !joint)
- {
- return;
- }
- const AZ::u32 actorId = actor->GetID();
- const AZStd::string& jointName = joint->GetNameString();
- const PhysicsSetup::ColliderConfigType colliderType = m_colliderWidget->GetColliderType();
- const size_t colliderIndex = m_colliderWidget->GetColliderIndex();
- const size_t instanceCount = parentDataNode->GetNumInstances();
- m_commandGroup.SetGroupName(AZStd::string::format("Adjust collider%s", instanceCount > 1 ? "s" : ""));
- for (size_t instanceIndex = 0; instanceIndex < instanceCount; ++instanceIndex)
- {
- CommandAdjustCollider* command = aznew CommandAdjustCollider(actorId, jointName, colliderType, colliderIndex);
- m_commandGroup.AddCommand(command);
- // ColliderConfiguration
- if (serializeContext->CanDowncast(classData->m_typeId, azrtti_typeid<Physics::ColliderConfiguration>(), classData->m_azRtti, nullptr))
- {
- const Physics::ColliderConfiguration* colliderConfig = static_cast<Physics::ColliderConfiguration*>(parentDataNode->GetInstance(instanceIndex));
- if (elementData->m_nameCrc == AZ_CRC("CollisionLayer", 0x39931633))
- {
- command->SetOldCollisionLayer(colliderConfig->m_collisionLayer);
- }
- if (elementData->m_nameCrc == AZ_CRC("CollisionGroupId", 0x84fe4bbe))
- {
- command->SetOldCollisionGroupId(colliderConfig->m_collisionGroupId);
- }
- if (elementData->m_nameCrc == AZ_CRC("Trigger", 0x1a6b0f5d))
- {
- command->SetOldIsTrigger(colliderConfig->m_isTrigger);
- }
- if (elementData->m_nameCrc == AZ_CRC("Position", 0x462ce4f5))
- {
- command->SetOldPosition(colliderConfig->m_position);
- }
- if (elementData->m_nameCrc == AZ_CRC("Rotation", 0x297c98f1))
- {
- command->SetOldRotation(colliderConfig->m_rotation);
- }
- if (elementData->m_nameCrc == AZ_CRC_CE("MaterialSlots"))
- {
- command->SetOldMaterialSlots(colliderConfig->m_materialSlots);
- }
- if (elementData->m_nameCrc == AZ_CRC("ColliderTag", 0x5e2963ad))
- {
- command->SetOldTag(colliderConfig->m_tag);
- }
- }
- // Box
- else if (serializeContext->CanDowncast(classData->m_typeId, azrtti_typeid<Physics::BoxShapeConfiguration>(), classData->m_azRtti, nullptr))
- {
- const Physics::BoxShapeConfiguration* boxShapeConfig = static_cast<Physics::BoxShapeConfiguration*>(parentDataNode->GetInstance(instanceIndex));
- if (elementData->m_nameCrc == AZ_CRC("Configuration", 0xa5e2a5d7))
- {
- command->SetOldDimensions(boxShapeConfig->m_dimensions);
- }
- }
- // Capsule
- else if (serializeContext->CanDowncast(classData->m_typeId, azrtti_typeid<Physics::CapsuleShapeConfiguration>(), classData->m_azRtti, nullptr))
- {
- const Physics::CapsuleShapeConfiguration* capsuleShapeConfig = static_cast<Physics::CapsuleShapeConfiguration*>(parentDataNode->GetInstance(instanceIndex));
- if (elementData->m_nameCrc == AZ_CRC("Radius", 0x3b7c6e5a))
- {
- command->SetOldRadius(capsuleShapeConfig->m_radius);
- }
- if (elementData->m_nameCrc == AZ_CRC("Height", 0xf54de50f))
- {
- command->SetOldHeight(capsuleShapeConfig->m_height);
- }
- }
- // Sphere
- else if (serializeContext->CanDowncast(classData->m_typeId, azrtti_typeid<Physics::SphereShapeConfiguration>(), classData->m_azRtti, nullptr))
- {
- const Physics::SphereShapeConfiguration* sphereShapeConfig = static_cast<Physics::SphereShapeConfiguration*>(parentDataNode->GetInstance(instanceIndex));
- if (elementData->m_nameCrc == AZ_CRC("Radius", 0x3b7c6e5a))
- {
- command->SetOldRadius(sphereShapeConfig->m_radius);
- }
- }
- }
- }
- void ColliderPropertyNotify::AfterPropertyModified([[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
- {
- PhysicsSetupManipulatorRequestBus::Broadcast(&PhysicsSetupManipulatorRequests::OnUnderlyingPropertiesChanged);
- }
- void ColliderPropertyNotify::SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* node)
- {
- if (m_commandGroup.IsEmpty())
- {
- return;
- }
- const AzToolsFramework::InstanceDataNode* parentDataNode = node->GetParent();
- if (!parentDataNode)
- {
- return;
- }
- const AZ::SerializeContext* serializeContext = parentDataNode->GetSerializeContext();
- const AZ::SerializeContext::ClassData* classData = parentDataNode->GetClassMetadata();
- const AZ::SerializeContext::ClassElement* elementData = node->GetElementMetadata();
- const Actor* actor = m_colliderWidget->GetActor();
- const Node* joint = m_colliderWidget->GetJoint();
- if (!actor || !joint)
- {
- return;
- }
- const PhysicsSetup::ColliderConfigType colliderType = m_colliderWidget->GetColliderType();
- const size_t instanceCount = parentDataNode->GetNumInstances();
- for (size_t instanceIndex = 0; instanceIndex < instanceCount; ++instanceIndex)
- {
- CommandAdjustCollider* command = static_cast<CommandAdjustCollider*>(m_commandGroup.GetCommand(instanceIndex));
- // ColliderConfiguration
- if (serializeContext->CanDowncast(classData->m_typeId, azrtti_typeid<Physics::ColliderConfiguration>(), classData->m_azRtti, nullptr))
- {
- const Physics::ColliderConfiguration* colliderConfig = static_cast<Physics::ColliderConfiguration*>(parentDataNode->GetInstance(instanceIndex));
- if (elementData->m_nameCrc == AZ_CRC("CollisionLayer", 0x39931633))
- {
- command->SetCollisionLayer(colliderConfig->m_collisionLayer);
- }
- if (elementData->m_nameCrc == AZ_CRC("CollisionGroupId", 0x84fe4bbe))
- {
- command->SetCollisionGroupId(colliderConfig->m_collisionGroupId);
- }
- if (elementData->m_nameCrc == AZ_CRC("Trigger", 0x1a6b0f5d))
- {
- command->SetIsTrigger(colliderConfig->m_isTrigger);
- }
- if (elementData->m_nameCrc == AZ_CRC("Position", 0x462ce4f5))
- {
- command->SetPosition(colliderConfig->m_position);
- }
- if (elementData->m_nameCrc == AZ_CRC("Rotation", 0x297c98f1))
- {
- command->SetRotation(colliderConfig->m_rotation);
- }
- if (elementData->m_nameCrc == AZ_CRC_CE("MaterialSlots"))
- {
- command->SetMaterialSlots(colliderConfig->m_materialSlots);
- }
- if (elementData->m_nameCrc == AZ_CRC("ColliderTag", 0x5e2963ad))
- {
- command->SetTag(colliderConfig->m_tag);
- CommandSimulatedObjectHelpers::ReplaceTag(actor, colliderType, /*oldTag=*/command->GetOldTag().value(), /*newTag=*/colliderConfig->m_tag, m_commandGroup);
- }
- }
- // Box
- else if (serializeContext->CanDowncast(classData->m_typeId, azrtti_typeid<Physics::BoxShapeConfiguration>(), classData->m_azRtti, nullptr))
- {
- const Physics::BoxShapeConfiguration* boxShapeConfig = static_cast<Physics::BoxShapeConfiguration*>(parentDataNode->GetInstance(instanceIndex));
- if (elementData->m_nameCrc == AZ_CRC("Configuration", 0xa5e2a5d7))
- {
- command->SetDimensions(boxShapeConfig->m_dimensions);
- }
- }
- // Capsule
- else if (serializeContext->CanDowncast(classData->m_typeId, azrtti_typeid<Physics::CapsuleShapeConfiguration>(), classData->m_azRtti, nullptr))
- {
- const Physics::CapsuleShapeConfiguration* capsuleShapeConfig = static_cast<Physics::CapsuleShapeConfiguration*>(parentDataNode->GetInstance(instanceIndex));
- if (elementData->m_nameCrc == AZ_CRC("Radius", 0x3b7c6e5a))
- {
- command->SetRadius(capsuleShapeConfig->m_radius);
- }
- if (elementData->m_nameCrc == AZ_CRC("Height", 0xf54de50f))
- {
- command->SetHeight(capsuleShapeConfig->m_height);
- }
- }
- // Sphere
- else if (serializeContext->CanDowncast(classData->m_typeId, azrtti_typeid<Physics::SphereShapeConfiguration>(), classData->m_azRtti, nullptr))
- {
- const Physics::SphereShapeConfiguration* sphereShapeConfig = static_cast<Physics::SphereShapeConfiguration*>(parentDataNode->GetInstance(instanceIndex));
- if (elementData->m_nameCrc == AZ_CRC("Radius", 0x3b7c6e5a))
- {
- command->SetRadius(sphereShapeConfig->m_radius);
- }
- }
- }
- AZStd::string result;
- CommandSystem::GetCommandManager()->ExecuteCommandGroup(m_commandGroup, result);
- m_commandGroup.Clear();
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ColliderWidget::ColliderWidget(QIcon* icon, QWidget* parent, AZ::SerializeContext* serializeContext)
- : AzQtComponents::Card(parent)
- , m_propertyNotify(AZStd::make_unique<ColliderPropertyNotify>(this))
- , m_icon(icon)
- {
- m_editor = new EMotionFX::ObjectEditor(serializeContext, m_propertyNotify.get(), this);
- setContentWidget(m_editor);
- setExpanded(true);
- connect(this, &AzQtComponents::Card::contextMenuRequested, this, &ColliderWidget::OnCardContextMenu);
- }
- void ColliderWidget::Update(Actor* actor, Node* joint, size_t colliderIndex, PhysicsSetup::ColliderConfigType colliderType, const AzPhysics::ShapeColliderPair& collider)
- {
- m_actor = actor;
- m_joint = joint;
- m_colliderIndex = colliderIndex;
- m_colliderType = colliderType;
- if (!collider.first || !collider.second)
- {
- m_editor->ClearInstances(true);
- m_collider = AzPhysics::ShapeColliderPair();
- return;
- }
- if (collider == m_collider)
- {
- m_editor->InvalidateAll();
- return;
- }
- const AZ::TypeId& shapeType = collider.second->RTTI_GetType();
- m_editor->ClearInstances(false);
- m_editor->AddInstance(collider.second.get(), shapeType);
- m_editor->AddInstance(collider.first.get(), collider.first->RTTI_GetType());
- m_collider = collider;
- AzQtComponents::CardHeader* cardHeader = header();
- cardHeader->setIcon(*m_icon);
- if (shapeType == azrtti_typeid<Physics::CapsuleShapeConfiguration>())
- {
- setTitle("Capsule");
- }
- else if (shapeType == azrtti_typeid<Physics::SphereShapeConfiguration>())
- {
- setTitle("Sphere");
- }
- else if (shapeType == azrtti_typeid<Physics::BoxShapeConfiguration>())
- {
- setTitle("Box");
- }
- else
- {
- setTitle("Unknown");
- }
- setProperty("colliderIndex", QVariant::fromValue(colliderIndex));
- setExpanded(true);
- }
- void ColliderWidget::Update()
- {
- if (!m_actor || !m_joint)
- {
- return;
- }
- setVisible(HasDisplayedNodes());
- }
- void ColliderWidget::SetFilterString(QString filterString)
- {
- m_editor->SetFilterString(filterString);
- Update();
- }
- bool ColliderWidget::HasDisplayedNodes() const
- {
- return m_editor->HasDisplayedNodes();
- }
- void ColliderWidget::OnCardContextMenu(const QPoint& position)
- {
- const AzQtComponents::Card* card = static_cast<AzQtComponents::Card*>(sender());
- const size_t colliderIndex = card->property("colliderIndex").value<size_t>();
- QMenu* contextMenu = new QMenu(this);
- contextMenu->setObjectName("EMFX.ColliderContainerWidget.ContextMenu");
- QAction* copyAction = contextMenu->addAction("Copy collider");
- copyAction->setObjectName("EMFX.ColliderContainerWidget.CopyColliderAction");
- copyAction->setProperty("colliderIndex", QVariant::fromValue(colliderIndex));
- connect(copyAction, &QAction::triggered, this, &ColliderWidget::OnCopyCollider);
- QAction* pasteAction = contextMenu->addAction("Paste collider");
- pasteAction->setObjectName("EMFX.ColliderContainerWidget.PasteColliderAction");
- pasteAction->setProperty("colliderIndex", QVariant::fromValue(colliderIndex));
- connect(pasteAction, &QAction::triggered, this, &ColliderWidget::OnPasteCollider);
- const QClipboard* clipboard = QGuiApplication::clipboard();
- const QMimeData* mimeData = clipboard->mimeData();
- const QByteArray clipboardContents = mimeData->data(ColliderHelpers::GetMimeTypeForColliderShape());
- pasteAction->setEnabled(!clipboardContents.isEmpty());
- QAction* deleteAction = contextMenu->addAction("Delete collider");
- deleteAction->setObjectName("EMFX.ColliderContainerWidget.DeleteColliderAction");
- deleteAction->setProperty("colliderIndex", QVariant::fromValue(colliderIndex));
- connect(deleteAction, &QAction::triggered, this, &ColliderWidget::OnRemoveCollider);
- QObject::connect(contextMenu, &QMenu::triggered, contextMenu, &QObject::deleteLater);
- if (!contextMenu->isEmpty())
- {
- contextMenu->popup(position);
- }
- }
- void ColliderWidget::OnCopyCollider()
- {
- QAction* action = static_cast<QAction*>(sender());
- const size_t colliderIndex = action->property("colliderIndex").value<size_t>();
- emit CopyCollider(colliderIndex);
- }
- void ColliderWidget::OnPasteCollider()
- {
- QAction* action = static_cast<QAction*>(sender());
- const int colliderIndex = action->property("colliderIndex").toInt();
- emit PasteCollider(colliderIndex);
- }
- void ColliderWidget::OnRemoveCollider()
- {
- QAction* action = static_cast<QAction*>(sender());
- const int colliderIndex = action->property("colliderIndex").toInt();
- emit RemoveCollider(colliderIndex);
- }
- void ColliderWidget::InvalidateEditorValues()
- {
- m_editor->InvalidateValues();
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- AddColliderButton::AddColliderButton(const QString& text, QWidget* parent, PhysicsSetup::ColliderConfigType copyToColliderType, const AZStd::vector<AZ::TypeId>& supportedColliderTypes)
- : QPushButton(text, parent)
- , m_supportedColliderTypes(supportedColliderTypes)
- , m_copyToColliderType(copyToColliderType)
- {
- setIcon(MysticQt::GetMysticQt()->FindIcon("Images/Icons/ArrowDownGray.png"));
- connect(this, &QPushButton::clicked, this, &AddColliderButton::OnCreateContextMenu);
- }
- void AddColliderButton::OnCreateContextMenu()
- {
- QMenu* contextMenu = new QMenu(this);
- contextMenu->setObjectName("EMFX.AddColliderButton.ContextMenu");
- AZStd::string actionName;
- for (const AZ::TypeId& typeId : m_supportedColliderTypes)
- {
- actionName = AZStd::string::format("Add %s", GetNameForColliderType(typeId).c_str());
- QAction* addBoxAction = contextMenu->addAction(actionName.c_str());
- addBoxAction->setProperty("typeId", typeId.ToString<AZStd::string>().c_str());
- connect(addBoxAction, &QAction::triggered, this, &AddColliderButton::OnAddColliderActionTriggered);
- }
- SkeletonModel* skeletonModel = nullptr;
- SkeletonOutlinerRequestBus::BroadcastResult(skeletonModel, &SkeletonOutlinerRequests::GetModel);
- // Add the copy from option
- contextMenu->addSeparator();
- if (m_copyToColliderType != PhysicsSetup::ColliderConfigType::Unknown)
- {
- for (int i = 0; i < PhysicsSetup::ColliderConfigType::Unknown; ++i)
- {
- const PhysicsSetup::ColliderConfigType copyFromType = static_cast<PhysicsSetup::ColliderConfigType>(i);
- if (copyFromType == m_copyToColliderType)
- {
- continue;
- }
- const char* visualName = PhysicsSetup::GetVisualNameForColliderConfigType(copyFromType);
- QAction* copyColliderAction = contextMenu->addAction(QString("Copy from %1").arg(visualName));
- copyColliderAction->setProperty("copyFromType", i);
- const bool canCopyFrom = ColliderHelpers::CanCopyFrom(skeletonModel->GetSelectionModel().selectedIndexes(), copyFromType);
- if (canCopyFrom)
- {
- connect(copyColliderAction, &QAction::triggered, this, &AddColliderButton::OnCopyColliderActionTriggered);
- }
- else
- {
- copyColliderAction->setEnabled(false);
- }
- }
- }
- contextMenu->setFixedWidth(width());
- if (!contextMenu->isEmpty())
- {
- contextMenu->popup(mapToGlobal(QPoint(0, height())));
- }
- connect(contextMenu, &QMenu::triggered, contextMenu, &QMenu::deleteLater);
- }
- void AddColliderButton::OnAddColliderActionTriggered()
- {
- QAction* action = static_cast<QAction*>(sender());
- const QByteArray typeString = action->property("typeId").toString().toUtf8();
- const AZ::TypeId& typeId = AZ::TypeId::CreateString(typeString.data(), typeString.size());
- emit AddCollider(typeId);
- }
- void AddColliderButton::OnCopyColliderActionTriggered()
- {
- AZ::Outcome<QModelIndexList> selectedRowIndicesOutcome;
- SkeletonOutlinerRequestBus::BroadcastResult(selectedRowIndicesOutcome, &SkeletonOutlinerRequests::GetSelectedRowIndices);
- if (!selectedRowIndicesOutcome.IsSuccess())
- {
- return;
- }
- const QModelIndexList& selectedRowIndices = selectedRowIndicesOutcome.GetValue();
- if (selectedRowIndices.empty())
- {
- return;
- }
- QAction* action = static_cast<QAction*>(sender());
- const PhysicsSetup::ColliderConfigType copyFromType = static_cast<PhysicsSetup::ColliderConfigType>(action->property("copyFromType").toInt());
- ColliderHelpers::CopyColliders(selectedRowIndices, copyFromType, m_copyToColliderType);
- }
- AZStd::string AddColliderButton::GetNameForColliderType(AZ::TypeId colliderType) const
- {
- if (colliderType == azrtti_typeid<Physics::BoxShapeConfiguration>())
- {
- return "box";
- }
- else if (colliderType == azrtti_typeid<Physics::CapsuleShapeConfiguration>())
- {
- return "capsule";
- }
- else if (colliderType == azrtti_typeid<Physics::SphereShapeConfiguration>())
- {
- return "sphere";
- }
- return colliderType.ToString<AZStd::string>();
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Align the layout spacing with the entity inspector.
- int ColliderContainerWidget::s_layoutSpacing = 13;
- ColliderContainerWidget::ColliderContainerWidget(const QIcon& colliderIcon, QWidget* parent)
- : QWidget(parent)
- , m_colliderIcon(colliderIcon)
- {
- m_layout = new QVBoxLayout();
- m_layout->setMargin(0);
- m_layout->setSpacing(s_layoutSpacing);
- setLayout(m_layout);
- m_commandCallback = new ColliderEditedCallback(this, /*executePreUndo*/false);
- CommandSystem::GetCommandManager()->RegisterCommandCallback(CommandAdjustCollider::s_commandName, m_commandCallback);
- }
- ColliderContainerWidget::~ColliderContainerWidget()
- {
- CommandSystem::GetCommandManager()->RemoveCommandCallback(m_commandCallback, /*delFromMem=*/true);
- }
- void ColliderContainerWidget::Update(Actor* actor, Node* joint, PhysicsSetup::ColliderConfigType colliderType, const AzPhysics::ShapeColliderPairList& colliders, AZ::SerializeContext* serializeContext)
- {
- m_actor = actor;
- m_joint = joint;
- m_colliderType = colliderType;
- const size_t numColliders = colliders.size();
- size_t numAvailableColliderWidgets = m_colliderWidgets.size();
- setVisible(numColliders > 0);
- // Create new collider widgets in case we don't have enough.
- if (numColliders > numAvailableColliderWidgets)
- {
- const int numWidgetsToCreate = static_cast<int>(numColliders) - static_cast<int>(numAvailableColliderWidgets);
- for (int i = 0; i < numWidgetsToCreate; ++i)
- {
- ColliderWidget* colliderWidget = new ColliderWidget(&m_colliderIcon, this, serializeContext);
- connect(colliderWidget, &ColliderWidget::RemoveCollider, this, &ColliderContainerWidget::RemoveCollider);
- connect(colliderWidget, &ColliderWidget::CopyCollider, this, &ColliderContainerWidget::CopyCollider);
- connect(colliderWidget, &ColliderWidget::PasteCollider, this, [this](size_t index) { PasteCollider(index, true); } );
- m_colliderWidgets.emplace_back(colliderWidget);
- m_layout->addWidget(colliderWidget, 0);
- }
- numAvailableColliderWidgets = m_colliderWidgets.size();
- }
- AZ_Assert(numAvailableColliderWidgets >= numColliders, "Not enough collider widgets available. Something went wrong with creating new ones.");
- for (size_t i = 0; i < numColliders; ++i)
- {
- ColliderWidget* colliderWidget = m_colliderWidgets[i];
- colliderWidget->Update(m_actor, m_joint, i, m_colliderType, colliders[i]);
- colliderWidget->show();
- }
- // Hide the collider widgets that are too much for the current node.
- for (size_t i = numColliders; i < numAvailableColliderWidgets; ++i)
- {
- m_colliderWidgets[i]->hide();
- m_colliderWidgets[i]->Update(nullptr, nullptr, InvalidIndex, PhysicsSetup::ColliderConfigType::Unknown, AzPhysics::ShapeColliderPair());
- }
- }
- void ColliderContainerWidget::Update()
- {
- for (ColliderWidget* colliderWidget : m_colliderWidgets)
- {
- colliderWidget->InvalidateEditorValues();
- colliderWidget->Update();
- }
- }
- void ColliderContainerWidget::Reset()
- {
- Update(nullptr, nullptr, PhysicsSetup::ColliderConfigType::Unknown, AzPhysics::ShapeColliderPairList(), nullptr);
- }
- void ColliderContainerWidget::SetFilterString(QString filterString)
- {
- for (auto* widget : m_colliderWidgets)
- {
- widget->SetFilterString(filterString);
- }
- }
- bool ColliderContainerWidget::HasVisibleColliders() const
- {
- return AZStd::any_of(
- m_colliderWidgets.begin(),
- m_colliderWidgets.end(),
- [](auto w)
- {
- return !w->isHidden();
- });
- }
- void ColliderContainerWidget::contextMenuEvent(QContextMenuEvent* event)
- {
- const QMimeData* mimeData = QGuiApplication::clipboard()->mimeData();
- const QByteArray clipboardContents = mimeData->data(ColliderHelpers::GetMimeTypeForColliderShape());
- int ypos = event->globalY();
- int index = 0;
- int curpos = mapToGlobal({0,0}).y();
- for (const ColliderWidget* card : m_colliderWidgets)
- {
- if (!card->GetActor())
- {
- break;
- }
- curpos = card->mapToGlobal({0,0}).y();
- if (curpos > ypos)
- {
- break;
- }
- ++index;
- }
- auto menu = new QMenu(this);
- connect(menu, &QMenu::triggered, &QObject::deleteLater);
- auto pasteNewColliderAction = new QAction("Paste collider", menu);
- pasteNewColliderAction->setEnabled(!clipboardContents.isEmpty());
- connect(pasteNewColliderAction, &QAction::triggered, this, [this, index]() { PasteCollider(index, false); } );
- menu->addAction(pasteNewColliderAction);
- menu->popup(event->globalPos());
- event->accept();
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ColliderContainerWidget::ColliderEditedCallback::ColliderEditedCallback(ColliderContainerWidget* parent, bool executePreUndo, bool executePreCommand)
- : MCore::Command::Callback(executePreUndo, executePreCommand)
- , m_widget(parent)
- {
- }
- bool ColliderContainerWidget::ColliderEditedCallback::Execute(MCore::Command* command, const MCore::CommandLine& commandLine)
- {
- AZ_UNUSED(command);
- AZ_UNUSED(commandLine);
- m_widget->Update();
- return true;
- }
- bool ColliderContainerWidget::ColliderEditedCallback::Undo(MCore::Command* command, const MCore::CommandLine& commandLine)
- {
- AZ_UNUSED(command);
- AZ_UNUSED(commandLine);
- m_widget->Update();
- return true;
- }
- } // namespace EMotionFX
|