Merge branch 'development' into cmake/warn_virtual

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2021-09-14 10:28:58 -07:00
58 changed files with 1096 additions and 661 deletions
@@ -221,24 +221,6 @@ namespace AzToolsFramework
using ViewportSettingsNotificationBus = AZ::EBus<ViewportSettingNotifications, ViewportEBusTraits>;
//! Requests to freeze the Viewport Input
//! Added to prevent a bug with the legacy CryEngine Viewport code that would
//! keep doing raycast tests even when no level is loaded, causing a crash.
class ViewportFreezeRequests
{
public:
//! Return if Viewport Input is frozen
virtual bool IsViewportInputFrozen() = 0;
//! Sets the Viewport Input freeze state
virtual void FreezeViewportInput(bool freeze) = 0;
protected:
~ViewportFreezeRequests() = default;
};
//! Type to inherit to implement ViewportFreezeRequests.
using ViewportFreezeRequestBus = AZ::EBus<ViewportFreezeRequests, ViewportEBusTraits>;
//! Viewport requests that are only guaranteed to be serviced by the Main Editor viewport.
class MainEditorViewportInteractionRequests
{
@@ -1770,6 +1770,12 @@ namespace AzToolsFramework
return false;
}
void EditorTransformComponentSelection::ChangeSelectedEntity(const AZ::EntityId entityId)
{
DeselectEntities();
SelectDeselect(entityId);
}
bool EditorTransformComponentSelection::HandleMouseInteraction(const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
{
AZ_PROFILE_FUNCTION(AzToolsFramework);
@@ -1821,202 +1827,239 @@ namespace AzToolsFramework
return true;
}
// double click to deselect all
if (Input::DeselectAll(mouseInteraction))
if (ed_viewportStickySelect)
{
// note: even if m_selectedEntityIds is technically empty, we
// may still have an entity selected that was clicked in the
// entity outliner - we still want to make sure the deselect all
// action clears the selection
DeselectEntities();
return false;
// double click to deselect all
if (Input::DeselectAll(mouseInteraction))
{
// note: even if m_selectedEntityIds is technically empty, we
// may still have an entity selected that was clicked in the
// entity outliner - we still want to make sure the deselect all
// action clears the selection
DeselectEntities();
return false;
}
}
// select/deselect (add/remove) entities with ctrl held
if (Input::AdditiveIndividualSelect(clickOutcome, mouseInteraction))
{
if (SelectDeselect(entityIdUnderCursor))
{
if (m_selectedEntityIds.empty())
{
m_pivotOverrideFrame.Reset();
}
return false;
}
}
if (!m_selectedEntityIds.empty())
{
// select/deselect (add/remove) entities with ctrl held
if (Input::AdditiveIndividualSelect(clickOutcome, mouseInteraction))
{
if (SelectDeselect(entityIdUnderCursor))
{
if (m_selectedEntityIds.empty())
{
m_pivotOverrideFrame.Reset();
}
return false;
}
}
// group copying/alignment to specific entity - 'ditto' position/orientation for group
if (Input::GroupDitto(mouseInteraction))
if (Input::GroupDitto(mouseInteraction) && PerformGroupDitto(entityIdUnderCursor))
{
if (entityIdUnderCursor.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM);
switch (m_mode)
{
case Mode::Rotation:
CopyOrientationToSelectedEntitiesGroup(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetUniformScale());
break;
case Mode::Translation:
CopyTranslationToSelectedEntitiesGroup(worldFromLocal.GetTranslation());
break;
default:
// do nothing
break;
}
return false;
}
return false;
}
// individual copying/alignment to specific entity - 'ditto' position/orientation for individual
if (Input::IndividualDitto(mouseInteraction))
if (Input::IndividualDitto(mouseInteraction) && PerformIndividualDitto(entityIdUnderCursor))
{
if (entityIdUnderCursor.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM);
switch (m_mode)
{
case Mode::Rotation:
CopyOrientationToSelectedEntitiesIndividual(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetUniformScale());
break;
case Mode::Translation:
CopyTranslationToSelectedEntitiesIndividual(worldFromLocal.GetTranslation());
break;
default:
// do nothing
break;
}
return false;
}
return false;
}
// try snapping to the terrain (if in Translation mode) and entity wasn't picked
if (Input::SnapTerrain(mouseInteraction))
{
for (AZ::EntityId entityId : m_selectedEntityIds)
{
ScopedUndoBatch::MarkEntityDirty(entityId);
}
if (m_mode == Mode::Translation)
{
const AZ::Vector3 finalSurfacePosition = PickTerrainPosition(mouseInteraction.m_mouseInteraction);
// handle modifier alternatives
if (Input::IndividualDitto(mouseInteraction))
{
CopyTranslationToSelectedEntitiesIndividual(finalSurfacePosition);
}
else if (Input::GroupDitto(mouseInteraction))
{
CopyTranslationToSelectedEntitiesGroup(finalSurfacePosition);
}
}
else if (m_mode == Mode::Rotation)
{
// handle modifier alternatives
if (Input::IndividualDitto(mouseInteraction))
{
CopyOrientationToSelectedEntitiesIndividual(AZ::Quaternion::CreateIdentity());
}
else if (Input::GroupDitto(mouseInteraction))
{
CopyOrientationToSelectedEntitiesGroup(AZ::Quaternion::CreateIdentity());
}
}
PerformSnapToTerrain(mouseInteraction);
return false;
}
// set manipulator pivot override translation or orientation (update manipulators)
if (Input::ManipulatorDitto(mouseInteraction))
{
if (m_entityIdManipulators.m_manipulators)
{
ScopedUndoBatch undoBatch(s_dittoManipulatorUndoRedoDesc);
auto manipulatorCommand =
AZStd::make_unique<EntityManipulatorCommand>(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName);
if (entityIdUnderCursor.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM);
// set orientation/translation to match picked entity
switch (m_mode)
{
case Mode::Rotation:
OverrideManipulatorOrientation(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Translation:
OverrideManipulatorTranslation(worldFromLocal.GetTranslation());
break;
case Mode::Scale:
// do nothing
break;
default:
break;
}
// only update pivot override when in translation or rotation mode
switch (m_mode)
{
case Mode::Rotation:
m_pivotOverrideFrame.m_pickTypes |= OptionalFrame::PickType::Orientation;
[[fallthrough]];
case Mode::Translation:
m_pivotOverrideFrame.m_pickTypes |= OptionalFrame::PickType::Translation;
m_pivotOverrideFrame.m_pickedEntityIdOverride = entityIdUnderCursor;
break;
case Mode::Scale:
// do nothing
break;
default:
break;
}
}
else
{
// match the same behavior as if we pressed Ctrl+R to reset the manipulator
DelegateClearManipulatorOverride();
}
manipulatorCommand->SetManipulatorAfter(EntityManipulatorCommand::State(
BuildPivotOverride(m_pivotOverrideFrame.HasTranslationOverride(), m_pivotOverrideFrame.HasOrientationOverride()),
m_entityIdManipulators.m_manipulators->GetLocalTransform(), entityIdUnderCursor));
manipulatorCommand->SetParent(undoBatch.GetUndoBatch());
manipulatorCommand.release();
}
PerformManipulatorDitto(entityIdUnderCursor);
return false;
}
return false;
if (ed_viewportStickySelect)
{
return false;
}
}
// standard toggle selection
if (Input::IndividualSelect(clickOutcome))
{
SelectDeselect(entityIdUnderCursor);
if (!ed_viewportStickySelect)
{
ChangeSelectedEntity(entityIdUnderCursor);
}
else
{
SelectDeselect(entityIdUnderCursor);
}
}
return false;
}
bool EditorTransformComponentSelection::PerformGroupDitto(const AZ::EntityId entityId)
{
if (entityId.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
switch (m_mode)
{
case Mode::Rotation:
CopyOrientationToSelectedEntitiesGroup(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetUniformScale());
break;
case Mode::Translation:
CopyTranslationToSelectedEntitiesGroup(worldFromLocal.GetTranslation());
break;
default:
// do nothing
break;
}
return true;
}
return false;
}
bool EditorTransformComponentSelection::PerformIndividualDitto(const AZ::EntityId entityId)
{
if (entityId.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
switch (m_mode)
{
case Mode::Rotation:
CopyOrientationToSelectedEntitiesIndividual(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetUniformScale());
break;
case Mode::Translation:
CopyTranslationToSelectedEntitiesIndividual(worldFromLocal.GetTranslation());
break;
default:
// do nothing
break;
}
return true;
}
return false;
}
void EditorTransformComponentSelection::PerformSnapToTerrain(const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
{
for (AZ::EntityId entityId : m_selectedEntityIds)
{
ScopedUndoBatch::MarkEntityDirty(entityId);
}
if (m_mode == Mode::Translation)
{
const AZ::Vector3 finalSurfacePosition = PickTerrainPosition(mouseInteraction.m_mouseInteraction);
// handle modifier alternatives
if (Input::IndividualDitto(mouseInteraction))
{
CopyTranslationToSelectedEntitiesIndividual(finalSurfacePosition);
}
else if (Input::GroupDitto(mouseInteraction))
{
CopyTranslationToSelectedEntitiesGroup(finalSurfacePosition);
}
}
else if (m_mode == Mode::Rotation)
{
// handle modifier alternatives
if (Input::IndividualDitto(mouseInteraction))
{
CopyOrientationToSelectedEntitiesIndividual(AZ::Quaternion::CreateIdentity());
}
else if (Input::GroupDitto(mouseInteraction))
{
CopyOrientationToSelectedEntitiesGroup(AZ::Quaternion::CreateIdentity());
}
}
}
void EditorTransformComponentSelection::PerformManipulatorDitto(const AZ::EntityId entityId)
{
if (m_entityIdManipulators.m_manipulators)
{
ScopedUndoBatch undoBatch(s_dittoManipulatorUndoRedoDesc);
auto manipulatorCommand =
AZStd::make_unique<EntityManipulatorCommand>(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName);
if (entityId.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
// set orientation/translation to match picked entity
switch (m_mode)
{
case Mode::Rotation:
OverrideManipulatorOrientation(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Translation:
OverrideManipulatorTranslation(worldFromLocal.GetTranslation());
break;
case Mode::Scale:
// do nothing
break;
default:
break;
}
// only update pivot override when in translation or rotation mode
switch (m_mode)
{
case Mode::Rotation:
m_pivotOverrideFrame.m_pickTypes |= OptionalFrame::PickType::Orientation;
[[fallthrough]];
case Mode::Translation:
m_pivotOverrideFrame.m_pickTypes |= OptionalFrame::PickType::Translation;
m_pivotOverrideFrame.m_pickedEntityIdOverride = entityId;
break;
case Mode::Scale:
// do nothing
break;
default:
break;
}
}
else
{
// match the same behavior as if we pressed Ctrl+R to reset the manipulator
DelegateClearManipulatorOverride();
}
manipulatorCommand->SetManipulatorAfter(EntityManipulatorCommand::State(
BuildPivotOverride(m_pivotOverrideFrame.HasTranslationOverride(), m_pivotOverrideFrame.HasOrientationOverride()),
m_entityIdManipulators.m_manipulators->GetLocalTransform(), entityId));
manipulatorCommand->SetParent(undoBatch.GetUndoBatch());
manipulatorCommand.release();
}
}
template<typename T>
static void AddAction(
AZStd::vector<AZStd::unique_ptr<QAction>>& actions,
@@ -207,6 +207,7 @@ namespace AzToolsFramework
void SetSelectedEntities(const EntityIdList& entityIds);
void DeselectEntities();
bool SelectDeselect(AZ::EntityId entityId);
void ChangeSelectedEntity(AZ::EntityId entityId);
void RefreshSelectedEntityIds();
void RefreshSelectedEntityIds(const EntityIdList& selectedEntityIds);
@@ -298,6 +299,11 @@ namespace AzToolsFramework
void SetEntityLocalRotation(AZ::EntityId entityId, const AZ::Vector3& localRotation);
void SetEntityLocalRotation(AZ::EntityId entityId, const AZ::Quaternion& localRotation);
bool PerformGroupDitto(AZ::EntityId entityId);
bool PerformIndividualDitto(AZ::EntityId entityId);
void PerformManipulatorDitto(AZ::EntityId entityId);
void PerformSnapToTerrain(const ViewportInteraction::MouseInteractionEvent& mouseInteraction);
//! Responsible for keeping the space cluster in sync with the current reference frame.
void UpdateSpaceCluster(ReferenceFrame referenceFrame);
@@ -614,7 +614,7 @@ namespace UnitTest
using EditorTransformComponentSelectionViewportPickingManipulatorTestFixture =
IndirectCallManipulatorViewportInteractionFixtureMixin<EditorTransformComponentSelectionViewportPickingFixture>;
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, SingleClickWithNoSelectionWillSelectEntity)
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, StickySingleClickWithNoSelectionWillSelectEntity)
{
AzToolsFramework::ed_viewportStickySelect = true;
@@ -637,19 +637,44 @@ namespace UnitTest
EXPECT_THAT(selectedEntitiesAfter.front(), Eq(m_entityId1));
}
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, SingleClickOffEntityWithSelectionWillNotDeselectEntity)
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, UnstickySingleClickWithNoSelectionWillSelectEntity)
{
AzToolsFramework::ed_viewportStickySelect = false;
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 entity1ScreenPosition = AzFramework::WorldToScreen(m_entity1WorldTranslation, m_cameraState);
// click the entity in the viewport
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity1ScreenPosition)->MouseLButtonDown()->MouseLButtonUp();
// entity is selected
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_THAT(selectedEntitiesAfter.size(), Eq(1));
EXPECT_THAT(selectedEntitiesAfter.front(), Eq(m_entityId1));
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
StickySingleClickOffEntityWithSelectionWillNotDeselectEntity)
{
AzToolsFramework::ed_viewportStickySelect = true;
PositionEntities();
PositionCamera(m_cameraState);
// position in space above the entity
// position in space above the entities
const auto clickOffPositionWorld = AZ::Vector3(5.0f, 15.0f, 12.0f);
AzToolsFramework::SelectEntity(m_entityId1);
// calculate the position in screen space of the initial position of the entity
// calculate the screen space position of the click
const auto clickOffPositionScreen = AzFramework::WorldToScreen(clickOffPositionWorld, m_cameraState);
// click the empty space in the viewport
@@ -662,9 +687,32 @@ namespace UnitTest
EXPECT_THAT(selectedEntitiesAfter.front(), Eq(m_entityId1));
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, UnstickySingleClickOffEntityWithSelectionWillDeselectEntity)
{
AzToolsFramework::ed_viewportStickySelect = false;
PositionEntities();
PositionCamera(m_cameraState);
AzToolsFramework::SelectEntity(m_entityId1);
// position in space above the entities
const auto clickOffPositionWorld = AZ::Vector3(5.0f, 15.0f, 12.0f);
// calculate the screen space position of the click
const auto clickOffPositionScreen = AzFramework::WorldToScreen(clickOffPositionWorld, m_cameraState);
// click the empty space in the viewport
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(clickOffPositionScreen)->MouseLButtonDown()->MouseLButtonUp();
// entity was deselected
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_TRUE(selectedEntitiesAfter.empty());
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
SingleClickOnNewEntityWithSelectionWillNotChangeSelectedEntity)
StickySingleClickOnNewEntityWithSelectionWillNotChangeSelectedEntity)
{
AzToolsFramework::ed_viewportStickySelect = true;
@@ -688,7 +736,31 @@ namespace UnitTest
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
CtrlSingleClickOnNewEntityWithSelectionWillAppendSelectedEntityToSelection)
UnstickySingleClickOnNewEntityWithSelectionWillChangeSelectedEntity)
{
AzToolsFramework::ed_viewportStickySelect = false;
PositionEntities();
PositionCamera(m_cameraState);
AzToolsFramework::SelectEntity(m_entityId1);
// calculate the position in screen space of the second entity
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
// click the entity in the viewport
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity2ScreenPosition)->MouseLButtonDown()->MouseLButtonUp();
// entity selection was changed
using ::testing::Eq;
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_THAT(selectedEntitiesAfter.size(), Eq(1));
EXPECT_THAT(selectedEntitiesAfter.front(), Eq(m_entityId2));
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
StickyCtrlSingleClickOnNewEntityWithSelectionWillAppendSelectedEntityToSelection)
{
AzToolsFramework::ed_viewportStickySelect = true;
@@ -715,7 +787,34 @@ namespace UnitTest
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
CtrlSingleClickOnEntityInSelectionWillRemoveEntityFromSelection)
UnstickyCtrlSingleClickOnNewEntityWithSelectionWillAppendSelectedEntityToSelection)
{
AzToolsFramework::ed_viewportStickySelect = false;
PositionEntities();
PositionCamera(m_cameraState);
AzToolsFramework::SelectEntity(m_entityId1);
// calculate the position in screen space of the second entity
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
// click the entity in the viewport
m_actionDispatcher->CameraState(m_cameraState)
->MousePosition(entity2ScreenPosition)
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
->MouseLButtonDown()
->MouseLButtonUp();
// entity selection was changed (one entity selected to two)
using ::testing::UnorderedElementsAre;
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1, m_entityId2));
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
StickyCtrlSingleClickOnEntityInSelectionWillRemoveEntityFromSelection)
{
AzToolsFramework::ed_viewportStickySelect = true;
@@ -740,7 +839,36 @@ namespace UnitTest
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1));
}
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, BoxSelectWithNoInitialSelectionAddsEntitiesToSelection)
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
UnstickyCtrlSingleClickOnEntityInSelectionWillRemoveEntityFromSelection)
{
AzToolsFramework::ed_viewportStickySelect = false;
PositionEntities();
PositionCamera(m_cameraState);
AzToolsFramework::SelectEntities({ m_entityId1, m_entityId2 });
// calculate the position in screen space of the second entity
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
// click the entity in the viewport
m_actionDispatcher->CameraState(m_cameraState)
->MousePosition(entity2ScreenPosition)
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
->MouseLButtonDown()
->MouseLButtonUp();
// entity selection was changed (entity2 was deselected)
using ::testing::UnorderedElementsAre;
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1));
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
BoxSelectWithNoInitialSelectionAddsEntitiesToSelection)
{
AzToolsFramework::ed_viewportStickySelect = true;
@@ -835,6 +963,32 @@ namespace UnitTest
EXPECT_TRUE(selectedEntitiesAfter.empty());
}
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, StickyDoubleClickWithSelectionWillDeselectEntities)
{
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));
// position in space above the entities
const auto clickOffPositionWorld = AZ::Vector3(5.0f, 15.0f, 12.0f);
// calculate the screen space position of the click
const auto clickOffPositionScreen = AzFramework::WorldToScreen(clickOffPositionWorld, m_cameraState);
// double click to deselect entities
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(clickOffPositionScreen)->MouseLButtonDoubleClick();
// no entities are selected
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_TRUE(selectedEntitiesAfter.empty());
}
using EditorTransformComponentSelectionManipulatorTestFixture =
IndirectCallManipulatorViewportInteractionFixtureMixin<EditorTransformComponentSelectionFixture>;