ActorGoalNodeHandler.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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 <Editor/PropertyWidgets/ActorGoalNodeHandler.h>
  9. #include <Editor/ActorEditorBus.h>
  10. #include <EMotionFX/Source/Attachment.h>
  11. #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
  12. #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/NodeSelectionWindow.h>
  13. #include <Editor/AnimGraphEditorBus.h>
  14. #include <QHBoxLayout>
  15. #include <QMessageBox>
  16. namespace EMotionFX
  17. {
  18. AZ_CLASS_ALLOCATOR_IMPL(ActorGoalNodePicker, EditorAllocator)
  19. AZ_CLASS_ALLOCATOR_IMPL(ActorGoalNodeHandler, EditorAllocator)
  20. ActorGoalNodePicker::ActorGoalNodePicker(QWidget* parent)
  21. : QWidget(parent)
  22. {
  23. QHBoxLayout* hLayout = new QHBoxLayout();
  24. hLayout->setMargin(0);
  25. m_pickButton = new QPushButton(this);
  26. connect(m_pickButton, &QPushButton::clicked, this, &ActorGoalNodePicker::OnPickClicked);
  27. hLayout->addWidget(m_pickButton);
  28. m_resetButton = new QPushButton(this);
  29. EMStudio::EMStudioManager::MakeTransparentButton(m_resetButton, "Images/Icons/Clear.svg", "Reset selection");
  30. connect(m_resetButton, &QPushButton::clicked, this, &ActorGoalNodePicker::OnResetClicked);
  31. hLayout->addWidget(m_resetButton);
  32. setLayout(hLayout);
  33. }
  34. void ActorGoalNodePicker::OnResetClicked()
  35. {
  36. if (m_goalNode.first.empty() && m_goalNode.second == 0)
  37. {
  38. return;
  39. }
  40. SetGoalNode(AZStd::make_pair(AZStd::string(), 0));
  41. emit SelectionChanged();
  42. }
  43. void ActorGoalNodePicker::UpdateInterface()
  44. {
  45. if (m_goalNode.first.empty())
  46. {
  47. m_pickButton->setText("Select node");
  48. m_resetButton->setVisible(false);
  49. }
  50. else
  51. {
  52. m_pickButton->setText(m_goalNode.first.c_str());
  53. m_resetButton->setVisible(true);
  54. }
  55. }
  56. void ActorGoalNodePicker::SetGoalNode(const AZStd::pair<AZStd::string, int>& goalNode)
  57. {
  58. m_goalNode = goalNode;
  59. UpdateInterface();
  60. }
  61. AZStd::pair<AZStd::string, int> ActorGoalNodePicker::GetGoalNode() const
  62. {
  63. return m_goalNode;
  64. }
  65. void ActorGoalNodePicker::OnPickClicked()
  66. {
  67. EMotionFX::ActorInstance* actorInstance = nullptr;
  68. ActorEditorRequestBus::BroadcastResult(actorInstance, &ActorEditorRequests::GetSelectedActorInstance);
  69. if (!actorInstance)
  70. {
  71. QMessageBox::warning(this, "No Actor Instance", "Cannot open node selection window. No valid actor instance selected.");
  72. return;
  73. }
  74. EMotionFX::Actor* actor = actorInstance->GetActor();
  75. // Create and show the node picker window
  76. EMStudio::NodeSelectionWindow nodeSelectionWindow(this, true);
  77. nodeSelectionWindow.GetNodeHierarchyWidget()->SetSelectionMode(true);
  78. CommandSystem::SelectionList prevSelection;
  79. EMotionFX::Node* node = actor->GetSkeleton()->FindNodeByName(m_goalNode.first.c_str());
  80. if (node)
  81. {
  82. prevSelection.AddNode(node);
  83. }
  84. AZStd::vector<uint32> actorInstanceIDs;
  85. // Add the current actor instance and all the ones it is attached to
  86. EMotionFX::ActorInstance* currentInstance = actorInstance;
  87. while (currentInstance)
  88. {
  89. actorInstanceIDs.emplace_back(currentInstance->GetID());
  90. EMotionFX::Attachment* attachment = currentInstance->GetSelfAttachment();
  91. if (attachment)
  92. {
  93. currentInstance = attachment->GetAttachToActorInstance();
  94. }
  95. else
  96. {
  97. currentInstance = nullptr;
  98. }
  99. }
  100. nodeSelectionWindow.Update(actorInstanceIDs, &prevSelection);
  101. nodeSelectionWindow.setModal(true);
  102. if (nodeSelectionWindow.exec() != QDialog::Rejected)
  103. {
  104. AZStd::vector<SelectionItem>& newSelection = nodeSelectionWindow.GetNodeHierarchyWidget()->GetSelectedItems();
  105. if (newSelection.size() == 1)
  106. {
  107. AZStd::string selectedNodeName = newSelection[0].GetNodeName();
  108. AZ::u32 selectedActorInstanceId = newSelection[0].m_actorInstanceId;
  109. const auto parentDepth = AZStd::find(begin(actorInstanceIDs), end(actorInstanceIDs), selectedActorInstanceId);
  110. AZ_Assert(parentDepth != end(actorInstanceIDs), "Cannot get parent depth. The selected actor instance was not shown in the selection window.");
  111. m_goalNode = {AZStd::move(selectedNodeName), static_cast<int>(AZStd::distance(begin(actorInstanceIDs), parentDepth))};
  112. UpdateInterface();
  113. emit SelectionChanged();
  114. }
  115. }
  116. }
  117. //---------------------------------------------------------------------------------------------------------------------------------------------------------
  118. AZ::u32 ActorGoalNodeHandler::GetHandlerName() const
  119. {
  120. return AZ_CRC("ActorGoalNode", 0xaf1e8a3a);
  121. }
  122. QWidget* ActorGoalNodeHandler::CreateGUI(QWidget* parent)
  123. {
  124. ActorGoalNodePicker* picker = aznew ActorGoalNodePicker(parent);
  125. connect(picker, &ActorGoalNodePicker::SelectionChanged, this, [picker]()
  126. {
  127. AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(
  128. &AzToolsFramework::PropertyEditorGUIMessages::Bus::Events::RequestWrite, picker);
  129. });
  130. return picker;
  131. }
  132. void ActorGoalNodeHandler::ConsumeAttribute(ActorGoalNodePicker* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, [[maybe_unused]] const char* debugName)
  133. {
  134. if (attrib == AZ::Edit::Attributes::ReadOnly)
  135. {
  136. bool value;
  137. if (attrValue->Read<bool>(value))
  138. {
  139. GUI->setEnabled(!value);
  140. }
  141. }
  142. }
  143. void ActorGoalNodeHandler::WriteGUIValuesIntoProperty([[maybe_unused]] size_t index, ActorGoalNodePicker* GUI, property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
  144. {
  145. instance = GUI->GetGoalNode();
  146. }
  147. bool ActorGoalNodeHandler::ReadValuesIntoGUI([[maybe_unused]] size_t index, ActorGoalNodePicker* GUI, const property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
  148. {
  149. QSignalBlocker signalBlocker(GUI);
  150. GUI->SetGoalNode(instance);
  151. return true;
  152. }
  153. } // namespace EMotionFX
  154. #include <Source/Editor/PropertyWidgets/moc_ActorGoalNodeHandler.cpp>