diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp index 61c7355273..851d2c5b6f 100644 --- a/Code/Editor/EditorViewportWidget.cpp +++ b/Code/Editor/EditorViewportWidget.cpp @@ -758,8 +758,7 @@ void EditorViewportWidget::RenderAll() m_manipulatorManager->DrawManipulators( *m_debugDisplay, GetCameraState(), BuildMouseInteractionInternal( - AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())), - AztfVi::BuildKeyboardModifiers(QGuiApplication::queryKeyboardModifiers()), + AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())), QueryKeyboardModifiers(), BuildMousePick(WidgetToViewport(mapFromGlobal(QCursor::pos()))))); m_debugDisplay->DepthTestOn(); } @@ -980,7 +979,12 @@ QWidget* EditorViewportWidget::GetWidgetForViewportContextMenu() bool EditorViewportWidget::ShowingWorldSpace() { - return AzToolsFramework::ViewportInteraction::BuildKeyboardModifiers(QGuiApplication::queryKeyboardModifiers()).Shift(); + return QueryKeyboardModifiers().Shift(); +} + +AzToolsFramework::ViewportInteraction::KeyboardModifiers EditorViewportWidget::QueryKeyboardModifiers() +{ + return AzToolsFramework::ViewportInteraction::BuildKeyboardModifiers(QGuiApplication::queryKeyboardModifiers()); } void EditorViewportWidget::SetViewportId(int id) diff --git a/Code/Editor/EditorViewportWidget.h b/Code/Editor/EditorViewportWidget.h index 426b7c5ad1..825d21a034 100644 --- a/Code/Editor/EditorViewportWidget.h +++ b/Code/Editor/EditorViewportWidget.h @@ -92,6 +92,7 @@ class SANDBOX_API EditorViewportWidget final , private AzToolsFramework::ViewportInteraction::ViewportFreezeRequestBus::Handler , private AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler , private AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler + , private AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler , private AzFramework::AssetCatalogEventBus::Handler , private AZ::RPI::SceneNotificationBus::Handler { @@ -205,7 +206,7 @@ private: bool IsViewportInputFrozen() override; void FreezeViewportInput(bool freeze) override; - // AzToolsFramework::MainEditorViewportInteractionRequestBus + // AzToolsFramework::MainEditorViewportInteractionRequestBus overrides ... AZ::EntityId PickEntity(const AzFramework::ScreenPoint& point) override; AZ::Vector3 PickTerrain(const AzFramework::ScreenPoint& point) override; float TerrainHeight(const AZ::Vector2& position) override; @@ -215,6 +216,9 @@ private: // EditorEntityViewportInteractionRequestBus overrides ... void FindVisibleEntities(AZStd::vector& visibleEntities) override; + // EditorModifierKeyRequestBus overrides ... + AzToolsFramework::ViewportInteraction::KeyboardModifiers QueryKeyboardModifiers() override; + // Camera::EditorCameraRequestBus overrides ... void SetViewFromEntityPerspective(const AZ::EntityId& entityId) override; void SetViewAndMovementLockFromEntityPerspective(const AZ::EntityId& entityId, bool lockCameraMovement) override; diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ActionDispatcher.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ActionDispatcher.h index 6ae09340e3..1b555a4a81 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ActionDispatcher.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ActionDispatcher.h @@ -8,15 +8,15 @@ #pragma once -#include +#include #include #include -#include +#include namespace AzManipulatorTestFramework { //! Base class for derived immediate and retained action dispatchers. - template + template class ActionDispatcher { public: @@ -31,7 +31,7 @@ namespace AzManipulatorTestFramework //! Enable/disable action logging. DerivedDispatcherT* LogActions(bool logging); //! Output a trace debug message. - template + template DerivedDispatcherT* Trace(const char* format, const Args&... args); //! Set the camera state. DerivedDispatcherT* CameraState(const AzFramework::CameraState& cameraState); @@ -60,8 +60,9 @@ namespace AzManipulatorTestFramework //! Break out to the debugger mid action sequence (note: do not leave uses in production code). DerivedDispatcherT* DebugBreak(); //! Enter component mode for the specified component type. - template + template DerivedDispatcherT* EnterComponentMode(); + protected: // Actions to be implemented by derived immediate and retained action dispatchers. virtual void EnableSnapToGridImpl() = 0; @@ -79,32 +80,50 @@ namespace AzManipulatorTestFramework virtual void SetSelectedEntityImpl(AZ::EntityId entity) = 0; virtual void SetSelectedEntitiesImpl(const AzToolsFramework::EntityIdList& entities) = 0; virtual void EnterComponentModeImpl(const AZ::Uuid& uuid) = 0; - template + template void Log(const char* format, const Args&... args); bool m_logging = false; + private: const char* KeyboardModifierString(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier); + static void DebugPrint(const char* format, ...); }; - template + template + void ActionDispatcher::DebugPrint(const char* format, ...) + { + va_list args; + va_start(args, format); + + vprintf(format, args); + printf("\n"); + + va_end(args); + } + + template template void ActionDispatcher::Log(const char* format, const Args&... args) { if (m_logging) { - AZ_Printf("ActionDispatcher", format, args...); + DebugPrint(format, args...); } } - template + template template DerivedDispatcherT* ActionDispatcher::Trace(const char* format, const Args&... args) { - Log(format, args...); + if (m_logging) + { + DebugPrint(format, args...); + } + return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::EnableSnapToGrid() { Log("Enabling SnapToGrid"); @@ -112,7 +131,7 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::DisableSnapToGrid() { Log("Disabling SnapToGrid"); @@ -120,15 +139,15 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::GridSize(float size) { - Log("GridSize: %f", size); + Log("GridSize: %.3f", size); GridSizeImpl(size); return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::LogActions(bool logging) { m_logging = logging; @@ -136,17 +155,16 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::CameraState(const AzFramework::CameraState& cameraState) { - Log("Camera state: p(%f, %f, %f) d(%f, %f, %f)", - float(cameraState.m_position.GetX()), float(cameraState.m_position.GetY()), float(cameraState.m_position.GetZ()), - float(cameraState.m_forward.GetX()), float(cameraState.m_forward.GetY()), float(cameraState.m_forward.GetZ())); + Log("Camera state: p(%.3f, %.3f, %.3f) d(%.3f, %.3f, %.3f)", cameraState.m_position.GetX(), cameraState.m_position.GetY(), + cameraState.m_position.GetZ(), cameraState.m_forward.GetX(), cameraState.m_forward.GetY(), cameraState.m_forward.GetZ()); CameraStateImpl(cameraState); return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::MouseLButtonDown() { Log("%s", "Mouse left button down"); @@ -154,14 +172,15 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::MouseLButtonUp() { Log("%s", "Mouse left button up"); MouseLButtonUpImpl(); return static_cast(this); } - template + + template const char* ActionDispatcher::KeyboardModifierString( const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) { @@ -176,11 +195,12 @@ namespace AzManipulatorTestFramework return "Shift"; case KeyboardModifier::None: return "None"; - default: return "Unknown modifier"; + default: + return "Unknown modifier"; } } - template + template DerivedDispatcherT* ActionDispatcher::KeyboardModifierDown( const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) { @@ -189,7 +209,7 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::KeyboardModifierUp( const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) { @@ -198,7 +218,7 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::MousePosition(const AzFramework::ScreenPoint& position) { Log("Mouse position: (%i, %i)", position.m_x, position.m_y); @@ -206,7 +226,7 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::ExpectManipulatorBeingInteracted() { Log("Expecting manipulator interacting"); @@ -214,7 +234,7 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::ExpectManipulatorNotBeingInteracted() { Log("Not expecting manipulator interacting"); @@ -222,27 +242,24 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template - DerivedDispatcherT* ActionDispatcher::SetEntityWorldTransform( - AZ::EntityId entityId, const AZ::Transform& transform) + template + DerivedDispatcherT* ActionDispatcher::SetEntityWorldTransform(AZ::EntityId entityId, const AZ::Transform& transform) { Log("Setting entity world transform: %s", AZ::ToString(transform).c_str()); SetEntityWorldTransformImpl(entityId, transform); return static_cast(this); } - template - DerivedDispatcherT* ActionDispatcher::SetSelectedEntity( - AZ::EntityId entity) + template + DerivedDispatcherT* ActionDispatcher::SetSelectedEntity(AZ::EntityId entity) { Log("Selecting entity: %u", static_cast(entity)); SetSelectedEntityImpl(entity); return static_cast(this); } - template - DerivedDispatcherT* ActionDispatcher::SetSelectedEntities( - const AzToolsFramework::EntityIdList& entities) + template + DerivedDispatcherT* ActionDispatcher::SetSelectedEntities(const AzToolsFramework::EntityIdList& entities) { for (const auto& entity : entities) { @@ -252,7 +269,7 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::EnterComponentMode(const AZ::Uuid& uuid) { Log("Entering component mode: %s", uuid.ToString().c_str()); @@ -260,7 +277,7 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template + template DerivedDispatcherT* ActionDispatcher::DebugBreak() { Log("Breaking to debugger"); @@ -268,8 +285,8 @@ namespace AzManipulatorTestFramework return static_cast(this); } - template - template + template + template DerivedDispatcherT* ActionDispatcher::EnterComponentMode() { EnterComponentMode(AZ::AzTypeInfo::Uuid()); diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ImmediateModeActionDispatcher.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ImmediateModeActionDispatcher.h index 89be56bab7..7a4773a37c 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ImmediateModeActionDispatcher.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ImmediateModeActionDispatcher.h @@ -10,11 +10,14 @@ #include #include +#include namespace AzManipulatorTestFramework { //! Dispatches actions immediately to the manipulators. - class ImmediateModeActionDispatcher : public ActionDispatcher + class ImmediateModeActionDispatcher + : public ActionDispatcher + , public AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler { using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier; using KeyboardModifiers = AzToolsFramework::ViewportInteraction::KeyboardModifiers; @@ -44,8 +47,8 @@ namespace AzManipulatorTestFramework //! Execute an arbitrary section of code inline in the action dispatcher. ImmediateModeActionDispatcher* ExecuteBlock(const AZStd::function& blockFn); - //! Get the current state of the keyboard modifiers. - KeyboardModifiers GetKeyboardModifiers() const; + // EditorModifierKeyRequestBus overrides ... + KeyboardModifiers QueryKeyboardModifiers() override; protected: // ActionDispatcher ... @@ -94,11 +97,11 @@ namespace AzManipulatorTestFramework inline ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetKeyboardModifiers(KeyboardModifiers& keyboardModifiers) { - keyboardModifiers = GetKeyboardModifiers(); + keyboardModifiers = QueryKeyboardModifiers(); return this; } - inline AzToolsFramework::ViewportInteraction::KeyboardModifiers ImmediateModeActionDispatcher::GetKeyboardModifiers() const + inline AzToolsFramework::ViewportInteraction::KeyboardModifiers ImmediateModeActionDispatcher::QueryKeyboardModifiers() { return GetMouseInteractionEvent()->m_mouseInteraction.m_keyboardModifiers; } diff --git a/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp b/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp index 4a6ed6a771..895899cf3f 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp @@ -32,9 +32,13 @@ namespace AzManipulatorTestFramework ImmediateModeActionDispatcher::ImmediateModeActionDispatcher(ManipulatorViewportInteraction& viewportManipulatorInteraction) : m_viewportManipulatorInteraction(viewportManipulatorInteraction) { + AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusConnect(); } - ImmediateModeActionDispatcher::~ImmediateModeActionDispatcher() = default; + ImmediateModeActionDispatcher::~ImmediateModeActionDispatcher() + { + AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusDisconnect(); + } void ImmediateModeActionDispatcher::MouseMoveAfterButton() { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp index 7b2ce53613..00f5b1ac47 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp @@ -657,8 +657,7 @@ namespace AzToolsFramework m_editorBoxSelect.InstallDisplayScene( [this, vertexBoxSelectData](const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& /*debugDisplay*/) { - const auto keyboardModifiers = ViewportInteraction::KeyboardModifiers( - ViewportInteraction::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); + const auto keyboardModifiers = AzToolsFramework::ViewportInteraction::QueryKeyboardModifiers(); // when modifiers change ensure we refresh box selection for immediate update if (keyboardModifiers != m_editorBoxSelect.PreviousModifiers()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h index fa4d8dfe11..c90c506a05 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h @@ -275,6 +275,29 @@ namespace AzToolsFramework using EditorEntityViewportInteractionRequestBus = AZ::EBus; + //! An interface to query editor modifier keys. + class EditorModifierKeyRequests : public AZ::EBusTraits + { + public: + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + + //! Returns the current state of the keyboard modifier keys. + virtual KeyboardModifiers QueryKeyboardModifiers() = 0; + + protected: + ~EditorModifierKeyRequests() = default; + }; + + using EditorModifierKeyRequestBus = AZ::EBus; + + inline KeyboardModifiers QueryKeyboardModifiers() + { + KeyboardModifiers keyboardModifiers; + EditorModifierKeyRequestBus::BroadcastResult(keyboardModifiers, &EditorModifierKeyRequestBus::Events::QueryKeyboardModifiers); + return keyboardModifiers; + } + //! Viewport requests for managing the viewport cursor state. class ViewportMouseCursorRequests { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.cpp index eafd37f199..a1b653225b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.cpp @@ -19,6 +19,13 @@ namespace AzToolsFramework static const AZ::Color s_boxSelectColor = AZ::Color(1.0f, 1.0f, 1.0f, 0.4f); static const float s_boxSelectLineWidth = 2.0f; + EditorBoxSelect::EditorBoxSelect() + { + // discard double click interval as box select is only interested in 'move' detection + // note: this also simplifies integration tests that do not have delays between presses + m_clickDetector.SetDoubleClickInterval(0.0f); + } + void EditorBoxSelect::HandleMouseInteraction(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) { AZ_PROFILE_FUNCTION(AzToolsFramework); @@ -95,8 +102,7 @@ namespace AzToolsFramework debugDisplay.DepthTestOn(); - m_previousModifiers = ViewportInteraction::KeyboardModifiers( - ViewportInteraction::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); + m_previousModifiers = AzToolsFramework::ViewportInteraction::QueryKeyboardModifiers(); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.h index f1c59f9fd8..3a638b80b6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.h @@ -29,7 +29,7 @@ namespace AzToolsFramework class EditorBoxSelect { public: - EditorBoxSelect() = default; + EditorBoxSelect(); //! Return if a box select action is currently taking place. bool Active() const { return m_boxSelectRegion.has_value(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index d7dd008c9e..7903668409 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -293,8 +293,8 @@ namespace AzToolsFramework } // poll and set the keyboard modifiers to ensure the mouse interaction is up to date - m_currentInteraction.m_keyboardModifiers = - AzToolsFramework::ViewportInteraction::BuildKeyboardModifiers(QGuiApplication::queryKeyboardModifiers()); + m_currentInteraction.m_keyboardModifiers = AzToolsFramework::ViewportInteraction::QueryKeyboardModifiers(); + // draw the manipulators const AzFramework::CameraState cameraState = GetCameraState(viewportInfo.m_viewportId); debugDisplay.DepthTestOff(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 6442559ede..3db8492d70 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -399,16 +399,18 @@ namespace AzToolsFramework // modifier has changed - swapped from additive to subtractive box select (or vice versa) if (previousKeyboardModifiers != currentKeyboardModifiers) { - for (AZ::EntityId entityId : potentialDeselectedEntityIds) + for (const AZ::EntityId& entityId : potentialDeselectedEntityIds) { editorTransformComponentSelection.AddEntityToSelection(entityId); } + potentialDeselectedEntityIds.clear(); - for (AZ::EntityId entityId : potentialSelectedEntityIds) + for (const AZ::EntityId& entityId : potentialSelectedEntityIds) { editorTransformComponentSelection.RemoveEntityFromSelection(entityId); } + potentialSelectedEntityIds.clear(); } @@ -1162,15 +1164,13 @@ namespace AzToolsFramework m_boxSelect.InstallDisplayScene( [this, entityBoxSelectData](const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { - const auto modifiers = ViewportInteraction::KeyboardModifiers( - ViewportInteraction::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); - - if (m_boxSelect.PreviousModifiers() != modifiers) + if (const auto keyboardModifiers = AzToolsFramework::ViewportInteraction::QueryKeyboardModifiers(); + m_boxSelect.PreviousModifiers() != keyboardModifiers) { EntityBoxSelectUpdateGeneral( m_boxSelect.BoxRegion(), *this, m_selectedEntityIds, entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect, entityBoxSelectData->m_potentialSelectedEntityIds, entityBoxSelectData->m_potentialDeselectedEntityIds, - *m_entityDataCache, viewportInfo.m_viewportId, modifiers, m_boxSelect.PreviousModifiers()); + *m_entityDataCache, viewportInfo.m_viewportId, keyboardModifiers, m_boxSelect.PreviousModifiers()); } debugDisplay.DepthTestOff(); @@ -3324,16 +3324,15 @@ namespace AzToolsFramework CheckDirtyEntityIds(); - const auto modifiers = - ViewportInteraction::KeyboardModifiers(ViewportInteraction::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); + const auto keyboardModifiers = AzToolsFramework::ViewportInteraction::QueryKeyboardModifiers(); m_cursorState.Update(); HandleAccents( - !m_selectedEntityIds.empty(), m_cachedEntityIdUnderCursor, modifiers.Ctrl(), m_hoveredEntityId, + !m_selectedEntityIds.empty(), m_cachedEntityIdUnderCursor, keyboardModifiers.Ctrl(), m_hoveredEntityId, ViewportInteraction::BuildMouseButtons(QGuiApplication::mouseButtons()), m_boxSelect.Active()); - const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock.value_or(ReferenceFrameFromModifiers(modifiers)); + const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock.value_or(ReferenceFrameFromModifiers(keyboardModifiers)); UpdateSpaceCluster(referenceFrame); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h index f528a11688..35d3587d0b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h @@ -235,7 +235,7 @@ namespace AzToolsFramework // can be returned to its previous state after an undo/redo operation void CreateEntityManipulatorDeselectCommand(ScopedUndoBatch& undoBatch); - // EditorTransformComponentSelectionRequestBus ... + // EditorTransformComponentSelectionRequestBus overrides ... Mode GetTransformMode() override; void SetTransformMode(Mode mode) override; void RefreshManipulators(RefreshType refreshType) override; @@ -252,34 +252,34 @@ namespace AzToolsFramework void CopyScaleToSelectedEntitiesIndividualWorld(float scale) override; void SnapSelectedEntitiesToWorldGrid(float gridSize) override; - // EditorManipulatorCommandUndoRedoRequestBus ... + // EditorManipulatorCommandUndoRedoRequestBus overrides ... void UndoRedoEntityManipulatorCommand(AZ::u8 pivotOverride, const AZ::Transform& transform, AZ::EntityId entityId) override; - // EditorContextMenuBus... + // EditorContextMenuBus overrides ... void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override; int GetMenuPosition() const override; AZStd::string GetMenuIdentifier() const override; - // EditorEventsBus ... + // EditorEventsBus overrides ... void OnEscape() override; - // ToolsApplicationNotificationBus ... + // ToolsApplicationNotificationBus overrides ... void BeforeEntitySelectionChanged() override; void AfterEntitySelectionChanged(const EntityIdList& newlySelectedEntities, const EntityIdList& newlyDeselectedEntities) override; - // TransformNotificationBus ... + // TransformNotificationBus overrides ... void OnTransformChanged(const AZ::Transform& localTM, const AZ::Transform& worldTM) override; - // Camera::EditorCameraNotificationBus ... + // Camera::EditorCameraNotificationBus overrides ... void OnViewportViewEntityChanged(const AZ::EntityId& newViewId) override; - // EditorContextVisibilityNotificationBus ... + // EditorContextVisibilityNotificationBus overrides ... void OnEntityVisibilityChanged(bool visibility) override; - // EditorContextLockComponentNotificationBus ... + // EditorContextLockComponentNotificationBus overrides ... void OnEntityLockChanged(bool locked) override; - // EditorComponentModeNotificationBus ... + // EditorComponentModeNotificationBus overrides ... void EnteredComponentMode(const AZStd::vector& componentModeTypes) override; void LeftComponentMode(const AZStd::vector& componentModeTypes) override; @@ -301,7 +301,7 @@ namespace AzToolsFramework //! Responsible for keeping the space cluster in sync with the current reference frame. void UpdateSpaceCluster(ReferenceFrame referenceFrame); - //! Hides/Shows all viewportUi toolbars. + //! Hides/Shows all viewportUi tool bars. void SetAllViewportUiVisible(bool visible); AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any). diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index dc6e38ecd5..8a958af567 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -238,10 +238,32 @@ namespace UnitTest m_entityId3 = createEntityWithBoundsFn("Entity3"); } - public: + void PositionEntities() + { + // the initial starting position of the entities + AZ::TransformBus::Event( + m_entityId1, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(m_entity1WorldTranslation)); + AZ::TransformBus::Event( + m_entityId2, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(m_entity2WorldTranslation)); + AZ::TransformBus::Event( + m_entityId3, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(m_entity3WorldTranslation)); + } + + static void PositionCamera(AzFramework::CameraState& cameraState) + { + // initial camera position (looking down the negative x-axis) + AzFramework::SetCameraTransform( + cameraState, + AZ::Transform::CreateFromQuaternionAndTranslation( + AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 15.0f, 10.0f))); + } + AZ::EntityId m_entityId1; AZ::EntityId m_entityId2; AZ::EntityId m_entityId3; + AZ::Vector3 m_entity1WorldTranslation = AZ::Vector3(5.0f, 15.0f, 10.0f); + AZ::Vector3 m_entity2WorldTranslation = AZ::Vector3(5.0f, 14.0f, 10.0f); + AZ::Vector3 m_entity3WorldTranslation = AZ::Vector3(5.0f, 16.0f, 10.0f); }; void ArrangeIndividualRotatedEntitySelection(const AzToolsFramework::EntityIdList& entityIds, const AZ::Quaternion& orientation) @@ -596,25 +618,18 @@ namespace UnitTest { AzToolsFramework::ed_viewportStickySelect = true; - // the initial starting position of the entity - const auto initialTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 15.0f, 10.0f)); - AZ::TransformBus::Event(m_entityId1, &AZ::TransformBus::Events::SetWorldTM, initialTransformWorld); - - // initial camera position (looking down the negative x-axis) - AzFramework::SetCameraTransform( - m_cameraState, - AZ::Transform::CreateFromQuaternionAndTranslation( - AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 15.0f, 10.0f))); + PositionEntities(); + PositionCamera(m_cameraState); using ::testing::Eq; auto selectedEntitiesBefore = SelectedEntities(); EXPECT_TRUE(selectedEntitiesBefore.empty()); // calculate the position in screen space of the initial entity position - const auto initialPositionScreen = AzFramework::WorldToScreen(initialTransformWorld.GetTranslation(), m_cameraState); + const auto entity1ScreenPosition = AzFramework::WorldToScreen(m_entity1WorldTranslation, m_cameraState); // click the entity in the viewport - m_actionDispatcher->CameraState(m_cameraState)->MousePosition(initialPositionScreen)->MouseLButtonDown()->MouseLButtonUp(); + m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity1ScreenPosition)->MouseLButtonDown()->MouseLButtonUp(); // entity is selected auto selectedEntitiesAfter = SelectedEntities(); @@ -626,19 +641,12 @@ namespace UnitTest { AzToolsFramework::ed_viewportStickySelect = true; - // the initial starting position of the entity - AZ::TransformBus::Event( - m_entityId1, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 15.0f, 10.0f))); + PositionEntities(); + PositionCamera(m_cameraState); // position in space above the entity const auto clickOffPositionWorld = AZ::Vector3(5.0f, 15.0f, 12.0f); - // initial camera position (looking down the negative x-axis) - AzFramework::SetCameraTransform( - m_cameraState, - AZ::Transform::CreateFromQuaternionAndTranslation( - AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 15.0f, 10.0f))); - AzToolsFramework::SelectEntity(m_entityId1); // calculate the position in screen space of the initial position of the entity @@ -660,30 +668,16 @@ namespace UnitTest { AzToolsFramework::ed_viewportStickySelect = true; - // the initial starting position of the entity - AZ::TransformBus::Event( - m_entityId1, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 15.0f, 10.0f))); - - const auto initialTransformWorldSecondEntity = AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 10.0f, 10.0f)); - AZ::TransformBus::Event(m_entityId2, &AZ::TransformBus::Events::SetWorldTM, initialTransformWorldSecondEntity); - - // initial camera position (looking down the negative x-axis) - AzFramework::SetCameraTransform( - m_cameraState, - AZ::Transform::CreateFromQuaternionAndTranslation( - AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 15.0f, 10.0f))); + PositionEntities(); + PositionCamera(m_cameraState); AzToolsFramework::SelectEntity(m_entityId1); // calculate the position in screen space of the second entity - const auto initialPositionScreenSecondEntity = - AzFramework::WorldToScreen(initialTransformWorldSecondEntity.GetTranslation(), m_cameraState); + const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState); // click the entity in the viewport - m_actionDispatcher->CameraState(m_cameraState) - ->MousePosition(initialPositionScreenSecondEntity) - ->MouseLButtonDown() - ->MouseLButtonUp(); + m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity2ScreenPosition)->MouseLButtonDown()->MouseLButtonUp(); // entity selection was not changed using ::testing::Eq; @@ -698,28 +692,17 @@ namespace UnitTest { AzToolsFramework::ed_viewportStickySelect = true; - // the initial starting position of the entity - AZ::TransformBus::Event( - m_entityId1, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 15.0f, 10.0f))); - - const auto initialTransformWorldSecondEntity = AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 10.0f, 10.0f)); - AZ::TransformBus::Event(m_entityId2, &AZ::TransformBus::Events::SetWorldTM, initialTransformWorldSecondEntity); - - // initial camera position (looking down the negative x-axis) - AzFramework::SetCameraTransform( - m_cameraState, - AZ::Transform::CreateFromQuaternionAndTranslation( - AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 15.0f, 10.0f))); + PositionEntities(); + PositionCamera(m_cameraState); AzToolsFramework::SelectEntity(m_entityId1); // calculate the position in screen space of the second entity - const auto initialPositionScreenSecondEntity = - AzFramework::WorldToScreen(initialTransformWorldSecondEntity.GetTranslation(), m_cameraState); + const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState); // click the entity in the viewport m_actionDispatcher->CameraState(m_cameraState) - ->MousePosition(initialPositionScreenSecondEntity) + ->MousePosition(entity2ScreenPosition) ->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control) ->MouseLButtonDown() ->MouseLButtonUp(); @@ -736,28 +719,17 @@ namespace UnitTest { AzToolsFramework::ed_viewportStickySelect = true; - // the initial starting position of the entity - AZ::TransformBus::Event( - m_entityId1, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 15.0f, 10.0f))); - - const auto initialTransformWorldSecondEntity = AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 10.0f, 10.0f)); - AZ::TransformBus::Event(m_entityId2, &AZ::TransformBus::Events::SetWorldTM, initialTransformWorldSecondEntity); - - // initial camera position (looking down the negative x-axis) - AzFramework::SetCameraTransform( - m_cameraState, - AZ::Transform::CreateFromQuaternionAndTranslation( - AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 15.0f, 10.0f))); + PositionEntities(); + PositionCamera(m_cameraState); AzToolsFramework::SelectEntities({ m_entityId1, m_entityId2 }); // calculate the position in screen space of the second entity - const auto initialPositionScreenSecondEntity = - AzFramework::WorldToScreen(initialTransformWorldSecondEntity.GetTranslation(), m_cameraState); + const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState); // click the entity in the viewport m_actionDispatcher->CameraState(m_cameraState) - ->MousePosition(initialPositionScreenSecondEntity) + ->MousePosition(entity2ScreenPosition) ->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control) ->MouseLButtonDown() ->MouseLButtonUp(); @@ -768,39 +740,26 @@ namespace UnitTest EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1)); } - TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, DISABLED_BoxSelectWithNoInitialSelectionAddsEntitiesToSelection) + TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, BoxSelectWithNoInitialSelectionAddsEntitiesToSelection) { AzToolsFramework::ed_viewportStickySelect = true; - // the initial starting position of the entities - AZ::TransformBus::Event( - m_entityId1, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 15.0f, 10.0f))); - AZ::TransformBus::Event( - m_entityId2, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 14.0f, 10.0f))); - AZ::TransformBus::Event( - m_entityId3, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 16.0f, 10.0f))); - - // initial camera position (looking down the negative x-axis) - AzFramework::SetCameraTransform( - m_cameraState, - AZ::Transform::CreateFromQuaternionAndTranslation( - AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 15.0f, 10.0f))); + PositionEntities(); + PositionCamera(m_cameraState); using ::testing::Eq; auto selectedEntitiesBefore = SelectedEntities(); EXPECT_THAT(selectedEntitiesBefore.size(), Eq(0)); // calculate the position in screen space of where to begin and end the box select action - const auto beginningPositionWorldBoxSelectStart = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 13.5f, 10.5f), m_cameraState); - const auto middlePositionWorldBoxSelectStart = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 15.0f, 10.0f), m_cameraState); - const auto endingPositionWorldBoxSelectStart = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 16.5f, 9.5f), m_cameraState); + const auto beginningPositionWorldBoxSelect = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 13.5f, 10.5f), m_cameraState); + const auto endingPositionWorldBoxSelect = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 16.5f, 9.5f), m_cameraState); // perform a box select in the viewport m_actionDispatcher->CameraState(m_cameraState) - ->MousePosition(beginningPositionWorldBoxSelectStart) + ->MousePosition(beginningPositionWorldBoxSelect) ->MouseLButtonDown() - ->MousePosition(middlePositionWorldBoxSelectStart) - ->MousePosition(endingPositionWorldBoxSelectStart) + ->MousePosition(endingPositionWorldBoxSelect) ->MouseLButtonUp(); // entities are selected @@ -809,6 +768,73 @@ namespace UnitTest EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1, m_entityId2, m_entityId3)); } + TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, BoxSelectWithSelectionAppendsEntitiesToSelection) + { + AzToolsFramework::ed_viewportStickySelect = true; + + PositionEntities(); + PositionCamera(m_cameraState); + + AzToolsFramework::SelectEntity(m_entityId1); + + using ::testing::UnorderedElementsAre; + auto selectedEntitiesBefore = SelectedEntities(); + EXPECT_THAT(selectedEntitiesBefore, UnorderedElementsAre(m_entityId1)); + + // calculate the position in screen space of where to begin and end the box select action + const auto beginningPositionWorldBoxSelect1 = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 14.5f, 10.5f), m_cameraState); + const auto endingPositionWorldBoxSelect1 = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 13.5f, 9.5f), m_cameraState); + const auto beginningPositionWorldBoxSelect2 = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 15.5f, 10.5f), m_cameraState); + const auto endingPositionWorldBoxSelect2 = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 16.5f, 9.5f), m_cameraState); + + // perform a box select in the viewport (going left and right) + m_actionDispatcher->CameraState(m_cameraState) + ->MousePosition(beginningPositionWorldBoxSelect1) + ->MouseLButtonDown() + ->MousePosition(endingPositionWorldBoxSelect1) + ->MouseLButtonUp() + ->MousePosition(beginningPositionWorldBoxSelect2) + ->MouseLButtonDown() + ->MousePosition(endingPositionWorldBoxSelect2) + ->MouseLButtonUp(); + + // entities are selected + auto selectedEntitiesAfter = SelectedEntities(); + EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1, m_entityId2, m_entityId3)); + } + + TEST_F( + EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, + BoxSelectHoldingCtrlWithSelectionRemovesEntitiesFromSelection) + { + AzToolsFramework::ed_viewportStickySelect = true; + + PositionEntities(); + PositionCamera(m_cameraState); + + AzToolsFramework::SelectEntities({ m_entityId1, m_entityId2, m_entityId3 }); + + using ::testing::UnorderedElementsAre; + auto selectedEntitiesBefore = SelectedEntities(); + EXPECT_THAT(selectedEntitiesBefore, UnorderedElementsAre(m_entityId1, m_entityId2, m_entityId3)); + + // calculate the position in screen space of where to begin and end the box select action + const auto beginningPositionWorldBoxSelect = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 13.5f, 10.5f), m_cameraState); + const auto endingPositionWorldBoxSelect = AzFramework::WorldToScreen(AZ::Vector3(5.0f, 16.5f, 9.5f), m_cameraState); + + // perform a box select in the viewport + m_actionDispatcher->CameraState(m_cameraState) + ->MousePosition(beginningPositionWorldBoxSelect) + ->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control) + ->MouseLButtonDown() + ->MousePosition(endingPositionWorldBoxSelect) + ->MouseLButtonUp(); + + // entities are selected + auto selectedEntitiesAfter = SelectedEntities(); + EXPECT_TRUE(selectedEntitiesAfter.empty()); + } + using EditorTransformComponentSelectionManipulatorTestFixture = IndirectCallManipulatorViewportInteractionFixtureMixin; diff --git a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponentMode.cpp b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponentMode.cpp index 13dc29599d..4bca7a9c96 100644 --- a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponentMode.cpp +++ b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponentMode.cpp @@ -52,8 +52,7 @@ namespace WhiteBox // default behavior for querying modifier keys (ask the QApplication) m_keyboardMofifierQueryFn = []() { - namespace vi = AzToolsFramework::ViewportInteraction; - return vi::KeyboardModifiers(vi::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); + return AzToolsFramework::ViewportInteraction::QueryKeyboardModifiers(); }; m_worldFromLocal = AzToolsFramework::WorldFromLocalWithUniformScale(entityComponentIdPair.GetEntityId()); diff --git a/Gems/WhiteBox/Code/Tests/WhiteBoxComponentTest.cpp b/Gems/WhiteBox/Code/Tests/WhiteBoxComponentTest.cpp index e2549a6126..0e93f38195 100644 --- a/Gems/WhiteBox/Code/Tests/WhiteBoxComponentTest.cpp +++ b/Gems/WhiteBox/Code/Tests/WhiteBoxComponentTest.cpp @@ -301,7 +301,7 @@ namespace UnitTest &WhiteBox::EditorWhiteBoxComponentModeRequestBus::Events::OverrideKeyboardModifierQuery, [this]() { - return m_actionDispatcher->GetKeyboardModifiers(); + return m_actionDispatcher->QueryKeyboardModifiers(); }); AzFramework::SetCameraTransform(