diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityTransformBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityTransformBus.h index 3fd9b24e7d..b250abe410 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityTransformBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityTransformBus.h @@ -1,47 +1,36 @@ /* -* 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 + * 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. + * + */ #pragma once +#include + namespace AzToolsFramework { using EntityIdList = AZStd::vector; - /*! - * Bus for notifications about entity transform changes from the editor viewport - */ - class EditorTransformChangeNotifications - : public AZ::EBusTraits + //! Notifications about entity transform changes from the editor. + class EditorTransformChangeNotifications : public AZ::EBusTraits { public: - virtual ~EditorTransformChangeNotifications() = default; + //! A notification that these entities had their transforms changed due to a user interaction in the editor. + //! @param entityIds Entities that had their transform changed. + virtual void OnEntityTransformChanged([[maybe_unused]] const AzToolsFramework::EntityIdList& entityIds) + { + } - /*! - * Notification that the specified entities are about to have their transforms changed due to user interaction in the editor viewport - * - * \param entityIds Entities about to be changed - */ - virtual void OnEntityTransformChanging(const AzToolsFramework::EntityIdList& /*entityIds*/) {}; - - /*! - * Notification that the specified entities had their transforms changed due to user interaction in the editor viewport - * - * \param entityIds Entities changed - */ - virtual void OnEntityTransformChanged(const AzToolsFramework::EntityIdList& /*entityIds*/) {}; + protected: + ~EditorTransformChangeNotifications() = default; }; using EditorTransformChangeNotificationBus = AZ::EBus; - } // namespace AzToolsFramework - diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp index bcbe98c3a7..a911888028 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -944,7 +945,7 @@ namespace AzToolsFramework return AZ::Success(); } - AZ::u32 TransformComponent::ParentChanged() + AZ::u32 TransformComponent::ParentChangedInspector() { AZ::u32 refreshLevel = AZ::Edit::PropertyRefreshLevels::None; @@ -974,12 +975,23 @@ namespace AzToolsFramework return refreshLevel; } - AZ::u32 TransformComponent::TransformChanged() + AZ::u32 TransformComponent::TransformChangedInspector() + { + if (TransformChanged()) + { + AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast( + &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged, + EntityIdList{ GetEntityId() }); + } + + return AZ::Edit::PropertyRefreshLevels::None; + } + + bool TransformComponent::TransformChanged() { if (!m_suppressTransformChangedEvent) { - auto parent = GetParentTransformComponent(); - if (parent) + if (auto parent = GetParentTransformComponent()) { OnTransformChanged(parent->GetLocalTM(), parent->GetWorldTM()); } @@ -987,13 +999,15 @@ namespace AzToolsFramework { OnTransformChanged(AZ::Transform::Identity(), AZ::Transform::Identity()); } + + return true; } - return AZ::Edit::PropertyRefreshLevels::None; + return false; } // This is called when our transform changes static state. - AZ::u32 TransformComponent::StaticChanged() + AZ::u32 TransformComponent::StaticChangedInspector() { AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( &AzToolsFramework::ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay, @@ -1175,10 +1189,10 @@ namespace AzToolsFramework Attribute(AZ::Edit::Attributes::AutoExpand, true)-> DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_parentEntityId, "Parent entity", "")-> Attribute(AZ::Edit::Attributes::ChangeValidate, &TransformComponent::ValidatePotentialParent)-> - Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::ParentChanged)-> + Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::ParentChangedInspector)-> Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::DontGatherReference | AZ::Edit::SliceFlags::NotPushableOnSliceRoot)-> DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_editorTransform, "Values", "")-> - Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::TransformChanged)-> + Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::TransformChangedInspector)-> Attribute(AZ::Edit::Attributes::AutoExpand, true)-> DataElement(AZ::Edit::UIHandlers::Button, &TransformComponent::m_addNonUniformScaleButton, "", "")-> Attribute(AZ::Edit::Attributes::ButtonText, "Add non-uniform scale")-> @@ -1189,7 +1203,7 @@ namespace AzToolsFramework EnumAttribute(AZ::TransformConfig::ParentActivationTransformMode::MaintainOriginalRelativeTransform, "Original relative transform")-> EnumAttribute(AZ::TransformConfig::ParentActivationTransformMode::MaintainCurrentWorldTransform, "Current world transform")-> DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_isStatic ,"Static", "Static entities are highly optimized and cannot be moved during runtime.")-> - Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::StaticChanged)-> + Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::StaticChangedInspector)-> DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_cachedWorldTransformParent, "Cached Parent Entity", "")-> Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::DontGatherReference | AZ::Edit::SliceFlags::NotPushable)-> Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)-> diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h index 80db5e10fb..30608b9680 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h @@ -182,9 +182,12 @@ namespace AzToolsFramework static void Reflect(AZ::ReflectContext* context); AZ::Outcome ValidatePotentialParent(void* newValue, const AZ::Uuid& valueType); - AZ::u32 ParentChanged(); - AZ::u32 TransformChanged(); - AZ::u32 StaticChanged(); + + AZ::u32 TransformChangedInspector(); + AZ::u32 ParentChangedInspector(); + AZ::u32 StaticChangedInspector(); + + bool TransformChanged(); AZ::Transform GetLocalTranslationTM() const; AZ::Transform GetLocalRotationTM() const; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp index 1a3bc0e5a3..84a58b1f79 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp @@ -165,11 +165,13 @@ namespace UnitTest void EditorEntityComponentChangeDetector::OnEntityTransformChanged( const AzToolsFramework::EntityIdList& entityIds) { + m_entityIds = entityIds; + for (const AZ::EntityId& entityId : entityIds) { if (const auto* entity = GetEntityById(entityId)) { - if (AZ::Component * transformComponent = entity->FindComponent()) + if (AZ::Component* transformComponent = entity->FindComponent()) { OnEntityComponentPropertyChanged(transformComponent->GetId()); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h index 276982d46d..6c146b3ac3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h @@ -239,6 +239,7 @@ namespace UnitTest bool PropertyDisplayInvalidated() const { return m_propertyDisplayInvalidated; } AZStd::vector m_componentIds; + AzToolsFramework::EntityIdList m_entityIds; private: // PropertyEditorEntityChangeNotificationBus ... diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index c503386ab5..cbf9e4ec28 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -999,7 +999,6 @@ namespace AzToolsFramework static void RefreshUiAfterChange(const EntityIdList& entitiyIds) { EditorTransformChangeNotificationBus::Broadcast(&EditorTransformChangeNotifications::OnEntityTransformChanged, entitiyIds); - ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); } @@ -1065,7 +1064,7 @@ namespace AzToolsFramework auto entityBoxSelectData = AZStd::make_shared(); m_boxSelect.InstallLeftMouseDown( - [this, entityBoxSelectData](const ViewportInteraction::MouseInteractionEvent& /*mouseInteraction*/) + [this, entityBoxSelectData]([[maybe_unused]] const ViewportInteraction::MouseInteractionEvent& mouseInteraction) { // begin selection undo/redo command entityBoxSelectData->m_boxSelectSelectionCommand = @@ -1263,8 +1262,12 @@ namespace AzToolsFramework }); translationManipulators->InstallLinearManipulatorMouseUpCallback( - [this]([[maybe_unused]] const LinearManipulator::Action& action) mutable + [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action) mutable { + AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast( + &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged, + manipulatorEntityIds->m_entityIds); + EndRecordManipulatorCommand(); }); @@ -1293,8 +1296,12 @@ namespace AzToolsFramework }); translationManipulators->InstallPlanarManipulatorMouseUpCallback( - [this, manipulatorEntityIds](const PlanarManipulator::Action& /*action*/) + [this, manipulatorEntityIds]([[maybe_unused]] const PlanarManipulator::Action& action) { + AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast( + &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged, + manipulatorEntityIds->m_entityIds); + EndRecordManipulatorCommand(); }); @@ -1322,8 +1329,12 @@ namespace AzToolsFramework }); translationManipulators->InstallSurfaceManipulatorMouseUpCallback( - [this, manipulatorEntityIds](const SurfaceManipulator::Action& /*action*/) + [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action) { + AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast( + &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged, + manipulatorEntityIds->m_entityIds); + EndRecordManipulatorCommand(); }); @@ -1360,7 +1371,7 @@ namespace AzToolsFramework AZStd::shared_ptr sharedRotationState = AZStd::make_shared(); rotationManipulators->InstallLeftMouseDownCallback( - [this, sharedRotationState](const AngularManipulator::Action& /*action*/) mutable -> void + [this, sharedRotationState]([[maybe_unused]] const AngularManipulator::Action& action) mutable -> void { sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); sharedRotationState->m_referenceFrameAtMouseDown = m_referenceFrame; @@ -1486,8 +1497,12 @@ namespace AzToolsFramework }); rotationManipulators->InstallLeftMouseUpCallback( - [this](const AngularManipulator::Action& /*action*/) + [this, sharedRotationState]([[maybe_unused]] const AngularManipulator::Action& action) { + AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast( + &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged, + sharedRotationState->m_entityIds); + EndRecordManipulatorCommand(); }); @@ -1533,6 +1548,10 @@ namespace AzToolsFramework auto uniformLeftMouseUpCallback = [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action) { + AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast( + &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged, + manipulatorEntityIds->m_entityIds); + m_entityIdManipulators.m_manipulators->SetLocalTransform(RecalculateAverageManipulatorTransform( m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); }; @@ -2370,7 +2389,7 @@ namespace AzToolsFramework AddAction( m_actions, { QKeySequence(Qt::Key_U) }, - /*ID_VIEWPORTUI_VISIBLE=*/50040, "Toggle ViewportUI", "Hide/Unhide Viewport UI", + /*ID_VIEWPORTUI_VISIBLE=*/50040, "Toggle Viewport UI", "Hide/Show Viewport UI", [this]() { SetViewportUiClusterVisible(m_transformModeClusterId, !m_viewportUiVisible); @@ -3139,7 +3158,7 @@ namespace AzToolsFramework } void EditorTransformComponentSelection::AfterEntitySelectionChanged( - const EntityIdList& /*newlySelectedEntities*/, const EntityIdList& /*newlyDeselectedEntities*/) + [[maybe_unused]] const EntityIdList& newlySelectedEntities, [[maybe_unused]] const EntityIdList& newlyDeselectedEntities) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -3534,17 +3553,17 @@ namespace AzToolsFramework RegenerateManipulators(); } - void EditorTransformComponentSelection::OnEntityVisibilityChanged(const bool /*visibility*/) + void EditorTransformComponentSelection::OnEntityVisibilityChanged([[maybe_unused]] const bool visibility) { m_selectedEntityIdsAndManipulatorsDirty = true; } - void EditorTransformComponentSelection::OnEntityLockChanged(const bool /*locked*/) + void EditorTransformComponentSelection::OnEntityLockChanged([[maybe_unused]] const bool locked) { m_selectedEntityIdsAndManipulatorsDirty = true; } - void EditorTransformComponentSelection::EnteredComponentMode(const AZStd::vector& /*componentModeTypes*/) + void EditorTransformComponentSelection::EnteredComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) { SetViewportUiClusterVisible(m_transformModeClusterId, false); @@ -3553,7 +3572,7 @@ namespace AzToolsFramework ToolsApplicationNotificationBus::Handler::BusDisconnect(); } - void EditorTransformComponentSelection::LeftComponentMode(const AZStd::vector& /*componentModeTypes*/) + void EditorTransformComponentSelection::LeftComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) { SetViewportUiClusterVisible(m_transformModeClusterId, true); diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index cbc81ba9b8..1d06dc9c33 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -451,6 +451,43 @@ namespace UnitTest EXPECT_TRUE(finalEntityTransform.IsClose(finalTransformWorld, 0.01f)); } + TEST_F(EditorTransformComponentSelectionManipulatorTestFixture, TranslatingEntityWithLinearManipulatorNotifiesOnEntityTransformChanged) + { + EditorEntityComponentChangeDetector editorEntityChangeDetector(m_entity1); + + // the initial starting position of the entity (in front and to the left of the camera) + const auto initialTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(-10.0f, 10.0f, 0.0f)); + // where the entity should end up (in front and to the right of the camera) + const auto finalTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 10.0f, 0.0f)); + + // calculate the position in screen space of the initial position of the entity + const auto initialPositionScreen = AzFramework::WorldToScreen(initialTransformWorld.GetTranslation(), m_cameraState); + // calculate the position in screen space of the final position of the entity + const auto finalPositionScreen = AzFramework::WorldToScreen(finalTransformWorld.GetTranslation(), m_cameraState); + + // move the entity to its starting position + AzToolsFramework::SetWorldTransform(m_entity1, initialTransformWorld); + // select the entity (this will cause the manipulators to appear in EditorTransformComponentSelection) + AzToolsFramework::SelectEntity(m_entity1); + + // create an offset along the linear manipulator pointing along the x-axis (perpendicular to the camera view) + const auto mouseOffsetOnManipulator = AzFramework::ScreenVector(10, 0); + // store the mouse down position on the manipulator + const auto mouseDownPosition = initialPositionScreen + mouseOffsetOnManipulator; + // final position in screen space of the mouse + const auto mouseMovePosition = finalPositionScreen + mouseOffsetOnManipulator; + + m_actionDispatcher->CameraState(m_cameraState) + ->MousePosition(mouseDownPosition) + ->MouseLButtonDown() + ->MousePosition(mouseMovePosition) + ->MouseLButtonUp(); + + // verify a EditorTransformChangeNotificationBus::OnEntityTransformChanged occurred + using ::testing::UnorderedElementsAreArray; + EXPECT_THAT(editorEntityChangeDetector.m_entityIds, UnorderedElementsAreArray(m_entityIds)); + } + // simple widget to listen for a mouse wheel event and then forward it on to the ViewportSelectionRequestBus class WheelEventWidget : public QWidget