Merge branch 'upstream/development' into LYN-6769_TestingRPCs

This commit is contained in:
Gene Walters
2021-12-03 10:40:48 -08:00
894 changed files with 11820 additions and 7018 deletions
@@ -486,9 +486,11 @@ namespace AZ
// Merge Command Line arguments
constexpr bool executeRegDumpCommands = false;
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands);
#if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD)
// Skip over merging the User Registry in non-debug and profile configurations
SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(*m_settingsRegistry, AZ_TRAIT_OS_PLATFORM_CODENAME, {});
#endif
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*m_settingsRegistry);
@@ -23,7 +23,7 @@ namespace AZ::SettingsRegistryConsoleUtils
inline constexpr const char* SettingsRegistryRemove = "sr_regremove";
inline constexpr const char* SettingsRegistryDump = "sr_regdump";
inline constexpr const char* SettingsRegistryDumpAll = "sr_regdumpall";
inline constexpr const char* SettingsRegistryMergeFile = "sr_regset-file";
inline constexpr const char* SettingsRegistryMergeFile = "sr_regset_file";
// RAII structure which owns the instances of the Settings Registry Console commands
// registered with an AZ Console
@@ -53,7 +53,7 @@ namespace AZ::SettingsRegistryConsoleUtils
//! "sr_regdumpall" accepts 0 arguments and dumps the entire settings registry
//! NOTE: this might result in a large amount of output to the console
//!
//! "sr_regset-file" accepts 1 or 2 arguments - <file-path> [<anchor json path>]
//! "sr_regset_file" accepts 1 or 2 arguments - <file-path> [<anchor json path>]
//! Merges the json formatted file <file path> into the settings registry underneath the root anchor ""
//! or <anchor json path> if supplied
[[nodiscard]] ConsoleFunctorHandle RegisterAzConsoleCommands(SettingsRegistryInterface& registry, AZ::IConsole& azConsole);
@@ -12,13 +12,57 @@
namespace AzFramework::Terrain
{
// Create a handler that can be accessed from Python scripts to receive terrain change notifications.
class TerrainDataNotificationHandler final
: public AzFramework::Terrain::TerrainDataNotificationBus::Handler
, public AZ::BehaviorEBusHandler
{
public:
AZ_EBUS_BEHAVIOR_BINDER(
TerrainDataNotificationHandler,
"{A83EF103-295A-4653-8279-F30FBF3F9037}",
AZ::SystemAllocator,
OnTerrainDataCreateBegin,
OnTerrainDataCreateEnd,
OnTerrainDataDestroyBegin,
OnTerrainDataDestroyEnd,
OnTerrainDataChanged);
void OnTerrainDataCreateBegin() override
{
Call(FN_OnTerrainDataCreateBegin);
}
void OnTerrainDataCreateEnd() override
{
Call(FN_OnTerrainDataCreateEnd);
}
void OnTerrainDataDestroyBegin() override
{
Call(FN_OnTerrainDataDestroyBegin);
}
void OnTerrainDataDestroyEnd() override
{
Call(FN_OnTerrainDataDestroyEnd);
}
void OnTerrainDataChanged(
const AZ::Aabb& dirtyRegion, AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask dataChangedMask) override
{
Call(FN_OnTerrainDataChanged, dirtyRegion, dataChangedMask);
}
};
void TerrainDataRequests::Reflect(AZ::ReflectContext* context)
{
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<AzFramework::Terrain::TerrainDataRequestBus>("TerrainDataRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Terrain")
->Event("GetHeight", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeight)
->Attribute(AZ::Script::Attributes::Module, "terrain")
->Event("GetNormal", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetNormal)
->Event("GetMaxSurfaceWeight", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetMaxSurfaceWeight)
->Event("GetMaxSurfaceWeightFromVector2",
@@ -34,8 +78,24 @@ namespace AzFramework::Terrain
->Event("GetTerrainAabb", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainAabb)
->Event("GetTerrainHeightQueryResolution",
&AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainHeightQueryResolution)
->Event("GetHeight", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeightVal)
->Event("GetHeightFromVector2", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeightValFromVector2)
->Event("GetHeightFromFloats", &AzFramework::Terrain::TerrainDataRequestBus::Events::GetHeightValFromFloats)
;
behaviorContext->EBus<AzFramework::Terrain::TerrainDataNotificationBus>("TerrainDataNotificationBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Terrain")
->Attribute(AZ::Script::Attributes::Module, "terrain")
->Event("OnTerrainDataCreateBegin", &AzFramework::Terrain::TerrainDataNotifications::OnTerrainDataCreateBegin)
->Event("OnTerrainDataCreateEnd", &AzFramework::Terrain::TerrainDataNotifications::OnTerrainDataCreateEnd)
->Event("OnTerrainDataDestroyBegin", &AzFramework::Terrain::TerrainDataNotifications::OnTerrainDataDestroyBegin)
->Event("OnTerrainDataDestroyEnd", &AzFramework::Terrain::TerrainDataNotifications::OnTerrainDataDestroyEnd)
->Event("OnTerrainDataChanged", &AzFramework::Terrain::TerrainDataNotifications::OnTerrainDataChanged)
->Handler<AzFramework::Terrain::TerrainDataNotificationHandler>()
;
}
//TerrainDataNotificationHandler::Reflect(context);
}
} // namespace AzFramework::Terrain
@@ -144,13 +144,31 @@ namespace AzFramework
return result;
}
SurfaceData::SurfacePoint BehaviorContextGetSurfacePointFromVector2(
const AZ::Vector2& inPosition,
Sampler sampleFilter = Sampler::DEFAULT) const
const AZ::Vector2& inPosition, Sampler sampleFilter = Sampler::DEFAULT) const
{
SurfaceData::SurfacePoint result;
GetSurfacePointFromVector2(inPosition, result, sampleFilter);
return result;
}
// Functions without the optional bool* parameter that can be used from Python tests.
float GetHeightVal(AZ::Vector3 position, Sampler sampler = Sampler::BILINEAR) const
{
bool terrainExists;
return GetHeight(position, sampler, &terrainExists);
}
float GetHeightValFromVector2(AZ::Vector2 position, Sampler sampler = Sampler::BILINEAR) const
{
bool terrainExists;
return GetHeightFromVector2(position, sampler, &terrainExists);
}
float GetHeightValFromFloats(float x, float y, Sampler sampler = Sampler::BILINEAR) const
{
bool terrainExists;
return GetHeightFromFloats(x, y, sampler, &terrainExists);
}
};
using TerrainDataRequestBus = AZ::EBus<TerrainDataRequests>;
@@ -5,6 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/XcbEventHandler.h>
+127 -48
View File
@@ -29,6 +29,13 @@ namespace InputUnitTests
////////////////////////////////////////////////////////////////////////////////////////////////
class InputTest : public ScopedAllocatorSetupFixture
{
public:
InputTest() : ScopedAllocatorSetupFixture()
{
// Many input tests are only valid if the GamePad device is supported on this platform.
m_gamepadSupported = InputDeviceGamepad::GetMaxSupportedGamepads() > 0;
}
protected:
////////////////////////////////////////////////////////////////////////////////////////////
void SetUp() override
@@ -46,6 +53,7 @@ namespace InputUnitTests
////////////////////////////////////////////////////////////////////////////////////////////
AZStd::unique_ptr<InputSystemComponent> m_inputSystemComponent;
bool m_gamepadSupported;
};
////////////////////////////////////////////////////////////////////////////////////////////////
@@ -78,12 +86,17 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputContext_ActivateDeactivate_Successfull)
#else
TEST_F(InputTest, InputContext_ActivateDeactivate_Successfull)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputContext_ActivateDeactivate_Successfull";
#else
SUCCEED() << "Skipping test InputContext_ActivateDeactivate_Successfull";
#endif
return;
}
// Create an input context (they are inactive by default).
InputContext inputContext("TestInputContext");
@@ -148,12 +161,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputContext_AddRemoveInputMapping_Successfull)
#else
TEST_F(InputTest, InputContext_AddRemoveInputMapping_Successfull)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputContext_AddRemoveInputMapping_Successfull";
#else
SUCCEED() << "Skipping test InputContext_AddRemoveInputMapping_Successfull";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -256,12 +275,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputContext_ConsumeProcessedInput_Consumed)
#else
TEST_F(InputTest, InputContext_ConsumeProcessedInput_Consumed)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputContext_ConsumeProcessedInput_Consumed";
#else
SUCCEED() << "Skipping test InputContext_ConsumeProcessedInput_Consumed";
#endif
return;
}
InputContext::InitData initData;
// Create a high priority input context that consumes input processed by any of its mappings.
@@ -340,12 +365,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputContext_FilteredInput_Mapped)
#else
TEST_F(InputTest, InputContext_FilteredInput_Mapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputContext_FilteredInput_Mapped";
#else
SUCCEED() << "Skipping test InputContext_FilteredInput_Mapped";
#endif
return;
}
// Create an input context that initially only listens for keyboard input.
InputContext::InitData initData;
initData.autoActivate = true;
@@ -413,12 +444,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingOr_AddRemoveSourceInput_Successful)
#else
TEST_F(InputTest, InputMappingOr_AddRemoveSourceInput_Successful)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingOr_AddRemoveSourceInput_Successful";
#else
SUCCEED() << "Skipping test InputMappingOr_AddRemoveSourceInput_Successful";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -491,12 +528,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingOr_SingleSourceInput_Mapped)
#else
TEST_F(InputTest, InputMappingOr_SingleSourceInput_Mapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingOr_SingleSourceInput_Mapped";
#else
SUCCEED() << "Skipping test InputMappingOr_SingleSourceInput_Mapped";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -558,12 +601,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingOr_MultipleSourceInputs_Mapped)
#else
TEST_F(InputTest, InputMappingOr_MultipleSourceInputs_Mapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingOr_MultipleSourceInputs_Mapped";
#else
SUCCEED() << "Skipping test InputMappingOr_MultipleSourceInputs_Mapped";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -650,12 +699,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingAnd_AddRemoveSourceInput_Successful)
#else
TEST_F(InputTest, InputMappingAnd_AddRemoveSourceInput_Successful)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingAnd_AddRemoveSourceInput_Successful";
#else
SUCCEED() << "Skipping test InputMappingAnd_AddRemoveSourceInput_Successful";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -728,12 +783,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingAnd_SingleSourceInput_Mapped)
#else
TEST_F(InputTest, InputMappingAnd_SingleSourceInput_Mapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingAnd_SingleSourceInput_Mapped";
#else
SUCCEED() << "Skipping test InputMappingAnd_SingleSourceInput_Mapped";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -795,12 +856,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingAnd_MultipleSourceInputs_Mapped)
#else
TEST_F(InputTest, InputMappingAnd_MultipleSourceInputs_Mapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingAnd_MultipleSourceInputs_Mapped";
#else
SUCCEED() << "Skipping test InputMappingAnd_MultipleSourceInputs_Mapped";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -909,12 +976,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingAnd_MultipleSourceInputsWithDifferentValues_ValuesAveraged)
#else
TEST_F(InputTest, InputMappingAnd_MultipleSourceInputsWithDifferentValues_ValuesAveraged)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingAnd_MultipleSourceInputsWithDifferentValues_ValuesAveraged";
#else
SUCCEED() << "Skipping test InputMappingAnd_MultipleSourceInputsWithDifferentValues_ValuesAveraged";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -969,12 +1042,18 @@ namespace InputUnitTests
}
////////////////////////////////////////////////////////////////////////////////////////////////
#if AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
TEST_F(InputTest, DISABLED_InputMappingAnd_MultipleSourceInputsFromTheSameInputDeviceTypeWithDifferentIndicies_NotMapped)
#else
TEST_F(InputTest, InputMappingAnd_MultipleSourceInputsFromTheSameInputDeviceTypeWithDifferentIndicies_NotMapped)
#endif // AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS
{
if (!m_gamepadSupported)
{
#if defined(GTEST_SKIP)
GTEST_SKIP() << "Skipping test InputMappingAnd_MultipleSourceInputsFromTheSameInputDeviceTypeWithDifferentIndicies_NotMapped";
#else
SUCCEED() << "Skipping test InputMappingAnd_MultipleSourceInputsFromTheSameInputDeviceTypeWithDifferentIndicies_NotMapped";
#endif
return;
}
// Create an input context and activate it.
InputContext inputContext("TestInputContext");
inputContext.Activate();
@@ -53,7 +53,6 @@ static void OptimizedSetParent(QWidget* widget, QWidget* parent)
namespace AzQtComponents
{
static const FancyDockingDropZoneConstants g_FancyDockingConstants;
// Constant for the threshold in pixels for snapping to edges while dragging for docking
static const int g_snapThresholdInPixels = 15;
@@ -155,7 +154,7 @@ namespace AzQtComponents
// Timer for updating our hovered drop zone opacity
QObject::connect(m_dropZoneHoverFadeInTimer, &QTimer::timeout, this, &FancyDocking::onDropZoneHoverFadeInUpdate);
m_dropZoneHoverFadeInTimer->setInterval(g_FancyDockingConstants.dropZoneHoverFadeUpdateIntervalMS);
m_dropZoneHoverFadeInTimer->setInterval(FancyDockingDropZoneConstants::dropZoneHoverFadeUpdateIntervalMS);
QIcon dragIcon = QIcon(QStringLiteral(":/Cursors/Grabbing.svg"));
m_dragCursor = QCursor(dragIcon.pixmap(16), 5, 2);
}
@@ -333,13 +332,13 @@ namespace AzQtComponents
*/
void FancyDocking::onDropZoneHoverFadeInUpdate()
{
const qreal dropZoneHoverOpacity = g_FancyDockingConstants.dropZoneHoverFadeIncrement + m_dropZoneState.dropZoneHoverOpacity();
const qreal dropZoneHoverOpacity = FancyDockingDropZoneConstants::dropZoneHoverFadeIncrement + m_dropZoneState.dropZoneHoverOpacity();
// Once we've reached the full drop zone opacity, cut it off in case we
// went over and stop the timer
if (dropZoneHoverOpacity >= g_FancyDockingConstants.dropZoneOpacity)
if (dropZoneHoverOpacity >= FancyDockingDropZoneConstants::dropZoneOpacity)
{
m_dropZoneState.setDropZoneHoverOpacity(g_FancyDockingConstants.dropZoneOpacity);
m_dropZoneState.setDropZoneHoverOpacity(FancyDockingDropZoneConstants::dropZoneOpacity);
m_dropZoneHoverFadeInTimer->stop();
}
else
@@ -792,12 +791,12 @@ namespace AzQtComponents
QPoint mainWindowTopLeft = multiscreenMapFromGlobal(mainWindow->mapToGlobal(mainWindowRect.topLeft()));
QPoint mainWindowTopRight = multiscreenMapFromGlobal(mainWindow->mapToGlobal(mainWindowRect.topRight()));
QPoint mainWindowBottomLeft = multiscreenMapFromGlobal(mainWindow->mapToGlobal(mainWindowRect.bottomLeft()));
QSize absoluteLeftRightSize(g_FancyDockingConstants.absoluteDropZoneSizeInPixels, mainWindowRect.height());
QSize absoluteLeftRightSize(FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels, mainWindowRect.height());
QRect absoluteLeftDropZone(mainWindowTopLeft, absoluteLeftRightSize);
QRect absoluteRightDropZone(mainWindowTopRight - QPoint(g_FancyDockingConstants.absoluteDropZoneSizeInPixels, 0), absoluteLeftRightSize);
QSize absoluteTopBottomSize(mainWindowRect.width(), g_FancyDockingConstants.absoluteDropZoneSizeInPixels);
QRect absoluteRightDropZone(mainWindowTopRight - QPoint(FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels, 0), absoluteLeftRightSize);
QSize absoluteTopBottomSize(mainWindowRect.width(), FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels);
QRect absoluteTopDropZone(mainWindowTopLeft, absoluteTopBottomSize);
QRect absoluteBottomDropZone(mainWindowBottomLeft - QPoint(0, g_FancyDockingConstants.absoluteDropZoneSizeInPixels), absoluteTopBottomSize);
QRect absoluteBottomDropZone(mainWindowBottomLeft - QPoint(0, FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels), absoluteTopBottomSize);
// If the drop target is a main window, then we will only show the absolute
// drop zone if the cursor is in that zone already
@@ -986,16 +985,16 @@ namespace AzQtComponents
switch (m_dropZoneState.absoluteDropZoneArea())
{
case Qt::LeftDockWidgetArea:
dockRect.setX(dockRect.x() + g_FancyDockingConstants.absoluteDropZoneSizeInPixels);
dockRect.setX(dockRect.x() + FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels);
break;
case Qt::RightDockWidgetArea:
dockRect.setWidth(dockRect.width() - g_FancyDockingConstants.absoluteDropZoneSizeInPixels);
dockRect.setWidth(dockRect.width() - FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels);
break;
case Qt::TopDockWidgetArea:
dockRect.setY(dockRect.y() + g_FancyDockingConstants.absoluteDropZoneSizeInPixels);
dockRect.setY(dockRect.y() + FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels);
break;
case Qt::BottomDockWidgetArea:
dockRect.setHeight(dockRect.height() - g_FancyDockingConstants.absoluteDropZoneSizeInPixels);
dockRect.setHeight(dockRect.height() - FancyDockingDropZoneConstants::absoluteDropZoneSizeInPixels);
break;
}
@@ -1034,15 +1033,15 @@ namespace AzQtComponents
// Set the drop zone width/height to the default, but if the dock widget
// width and/or height is below the threshold, then switch to scaling them
// down accordingly
int dropZoneWidth = g_FancyDockingConstants.dropZoneSizeInPixels;
if (dockWidth < g_FancyDockingConstants.minDockSizeBeforeDropZoneScalingInPixels)
int dropZoneWidth = FancyDockingDropZoneConstants::dropZoneSizeInPixels;
if (dockWidth < FancyDockingDropZoneConstants::minDockSizeBeforeDropZoneScalingInPixels)
{
dropZoneWidth = aznumeric_cast<int>(dockWidth * g_FancyDockingConstants.dropZoneScaleFactor);
dropZoneWidth = aznumeric_cast<int>(dockWidth * FancyDockingDropZoneConstants::dropZoneScaleFactor);
}
int dropZoneHeight = g_FancyDockingConstants.dropZoneSizeInPixels;
if (dockHeight < g_FancyDockingConstants.minDockSizeBeforeDropZoneScalingInPixels)
int dropZoneHeight = FancyDockingDropZoneConstants::dropZoneSizeInPixels;
if (dockHeight < FancyDockingDropZoneConstants::minDockSizeBeforeDropZoneScalingInPixels)
{
dropZoneHeight = aznumeric_cast<int>(dockHeight * g_FancyDockingConstants.dropZoneScaleFactor);
dropZoneHeight = aznumeric_cast<int>(dockHeight * FancyDockingDropZoneConstants::dropZoneScaleFactor);
}
// Calculate the inner corners to be used when constructing the drop zone polygons
@@ -1078,7 +1077,7 @@ namespace AzQtComponents
int innerDropZoneWidth = m_dropZoneState.innerDropZoneRect().width();
int innerDropZoneHeight = m_dropZoneState.innerDropZoneRect().height();
int centerDropZoneDiameter = (innerDropZoneWidth < innerDropZoneHeight) ? innerDropZoneWidth : innerDropZoneHeight;
centerDropZoneDiameter = aznumeric_cast<int>(centerDropZoneDiameter * g_FancyDockingConstants.centerTabDropZoneScale);
centerDropZoneDiameter = aznumeric_cast<int>(centerDropZoneDiameter * FancyDockingDropZoneConstants::centerTabDropZoneScale);
// Setup our center tab drop zone
const QSize centerDropZoneSize(centerDropZoneDiameter, centerDropZoneDiameter);
@@ -1986,7 +1985,7 @@ namespace AzQtComponents
// hasn't faded in all the way yet, then ignore the drop zone area
// which will make the widget floating
bool modifiedKeyPressed = FancyDockingDropZoneWidget::CheckModifierKey();
if (modifiedKeyPressed || m_dropZoneState.dropZoneHoverOpacity() != g_FancyDockingConstants.dropZoneOpacity)
if (modifiedKeyPressed || m_dropZoneState.dropZoneHoverOpacity() != FancyDockingDropZoneConstants::dropZoneOpacity)
{
area = Qt::NoDockWidgetArea;
}
@@ -3026,7 +3025,7 @@ namespace AzQtComponents
{
bool modifiedKeyPressed = FancyDockingDropZoneWidget::CheckModifierKey();
m_ghostWidget->setWindowOpacity(modifiedKeyPressed ? 1.0f : g_FancyDockingConstants.draggingDockWidgetOpacity);
m_ghostWidget->setWindowOpacity(modifiedKeyPressed ? 1.0f : FancyDockingDropZoneConstants::draggingDockWidgetOpacity);
m_ghostWidget->setPixmap(m_state.dockWidgetScreenGrab.screenGrab, m_state.placeholder(), m_state.placeholderScreen());
}
}
@@ -19,26 +19,6 @@
namespace AzQtComponents
{
static const FancyDockingDropZoneConstants g_Constants;
FancyDockingDropZoneConstants::FancyDockingDropZoneConstants()
{
draggingDockWidgetOpacity = 0.6;
dropZoneOpacity = 0.4;
dropZoneSizeInPixels = 40;
minDockSizeBeforeDropZoneScalingInPixels = dropZoneSizeInPixels * 3;
dropZoneScaleFactor = 0.25;
centerTabDropZoneScale = 0.5;
centerTabIconScale = 0.5;
dropZoneColor = QColor(155, 155, 155);
dropZoneBorderColor = Qt::black;
dropZoneBorderInPixels = 1;
absoluteDropZoneSizeInPixels = 25;
dockingTargetDelayMS = 110;
dropZoneHoverFadeUpdateIntervalMS = 20;
dropZoneHoverFadeIncrement = dropZoneOpacity / (dockingTargetDelayMS / dropZoneHoverFadeUpdateIntervalMS);
centerDropZoneIconPath = QString(":/stylesheet/img/UI20/docking/tabs_icon.svg");
}
FancyDockingDropZoneWidget::FancyDockingDropZoneWidget(QMainWindow* mainWindow, QWidget* coordinatesRelativeTo, QScreen* screen, FancyDockingDropZoneState* dropZoneState)
// NOTE: this will not work with multiple monitors if this widget has a parent. The floating drop zone
@@ -154,7 +134,7 @@ namespace AzQtComponents
// Draw all of the normal drop zones if they exist (if a dock widget is hovered over)
painter.setPen(Qt::NoPen);
painter.setOpacity(g_Constants.dropZoneOpacity);
painter.setOpacity(FancyDockingDropZoneConstants::dropZoneOpacity);
auto dropZones = m_dropZoneState->dropZones();
for (auto it = dropZones.cbegin(); it != dropZones.cend(); ++it)
{
@@ -189,7 +169,7 @@ namespace AzQtComponents
// Otherwise, set the normal color
else
{
painter.setBrush(g_Constants.dropZoneColor);
painter.setBrush(FancyDockingDropZoneConstants::dropZoneColor);
}
// negate the window position to offset everything by that much
@@ -214,8 +194,8 @@ namespace AzQtComponents
// Scale the tabs icon based on the drop zone size and our specified offset
// Doing this through QIcon to make sure that SVG is rendered already in desired resolution
const QSize& dropZoneSize = dropZoneRect.size();
const QSize requestedIconSize = dropZoneSize * g_Constants.centerTabIconScale;
const QIcon dropZoneIcon = QIcon(g_Constants.centerDropZoneIconPath);
const QSize requestedIconSize = dropZoneSize * FancyDockingDropZoneConstants::centerTabIconScale;
const QIcon dropZoneIcon = QIcon(FancyDockingDropZoneConstants::centerDropZoneIconPath);
const QPixmap dropZonePixmap = dropZoneIcon.pixmap(requestedIconSize);
const QSize receivedIconSize = dropZoneIcon.actualSize(requestedIconSize);
@@ -264,7 +244,7 @@ namespace AzQtComponents
}
else
{
painter.setBrush(g_Constants.dropZoneColor);
painter.setBrush(FancyDockingDropZoneConstants::dropZoneColor);
}
painter.drawRect(absoluteDropZoneRect);
@@ -313,8 +293,8 @@ namespace AzQtComponents
const QPoint innerBottomRight = innerDropZoneRect.bottomRight();
// Draw the lines using the appropriate pen
QPen dropZoneBorderPen(g_Constants.dropZoneBorderColor);
dropZoneBorderPen.setWidth(g_Constants.dropZoneBorderInPixels);
QPen dropZoneBorderPen(FancyDockingDropZoneConstants::dropZoneBorderColor);
dropZoneBorderPen.setWidth(FancyDockingDropZoneConstants::dropZoneBorderInPixels);
painter.setPen(dropZoneBorderPen);
painter.setOpacity(1);
painter.drawLine(topLeft, innerTopLeft);
@@ -28,63 +28,58 @@ class QPainter;
namespace AzQtComponents
{
struct AZ_QT_COMPONENTS_API FancyDockingDropZoneConstants
namespace FancyDockingDropZoneConstants
{
// Constant for the opacity of the screen grab for the dock widget being dragged
qreal draggingDockWidgetOpacity;
static constexpr qreal draggingDockWidgetOpacity = 0.6;
// Constant for the opacity of the normal drop zones
qreal dropZoneOpacity;
static constexpr qreal dropZoneOpacity = 0.4;
// Constant for the default drop zone size (in pixels)
int dropZoneSizeInPixels;
static constexpr int dropZoneSizeInPixels = 40;
// Constant for the dock width/height size (in pixels) before we need to start
// scaling down the drop zone sizes, or else they will overlap with the center
// tab icon or each other
int minDockSizeBeforeDropZoneScalingInPixels;
static constexpr int minDockSizeBeforeDropZoneScalingInPixels = dropZoneSizeInPixels * 3;
// Constant for the factor by which we must scale down the drop zone sizes once
// the dock width/height size is too small
qreal dropZoneScaleFactor;
static constexpr qreal dropZoneScaleFactor = 0.25;
// Constant for the percentage to scale down the inner drop zone rectangle for the center tab drop zone
qreal centerTabDropZoneScale;
static constexpr qreal centerTabDropZoneScale = 0.5;
// Constant for the percentage to scale down the center tab drop zone for the center tab icon
qreal centerTabIconScale;
static constexpr qreal centerTabIconScale = 0.5;
// Constant for the drop zone hotspot default color
QColor dropZoneColor;
static const QColor dropZoneColor = QColor(155, 155, 155);
// Constant for the drop zone border color
QColor dropZoneBorderColor;
static const QColor dropZoneBorderColor = Qt::black;
// Constant for the border width in pixels separating the drop zones
int dropZoneBorderInPixels;
static constexpr int dropZoneBorderInPixels = 1;
// Constant for the border width in pixels separating the drop zones
int absoluteDropZoneSizeInPixels;
static constexpr int absoluteDropZoneSizeInPixels = 25;
// Constant for the delay (in milliseconds) before a drop zone becomes active
// once it is hovered over
int dockingTargetDelayMS;
static constexpr int dockingTargetDelayMS = 110;
// Constant for the rate at which we will update (fade in) the drop zone opacity
// when hovered over (in milliseconds)
int dropZoneHoverFadeUpdateIntervalMS;
static constexpr int dropZoneHoverFadeUpdateIntervalMS = 20;
// Constant for the incremental opacity increase for the hovered drop zone
// that will fade in to the full drop zone opacity in the desired time
qreal dropZoneHoverFadeIncrement;
static constexpr qreal dropZoneHoverFadeIncrement = dropZoneOpacity / (dockingTargetDelayMS / dropZoneHoverFadeUpdateIntervalMS);
// Constant for the path to the center drop zone tabs icon
QString centerDropZoneIconPath;
FancyDockingDropZoneConstants();
FancyDockingDropZoneConstants(const FancyDockingDropZoneConstants&) = delete;
FancyDockingDropZoneConstants& operator=(const FancyDockingDropZoneConstants&) = delete;
static const QString centerDropZoneIconPath = QStringLiteral(":/stylesheet/img/UI20/docking/tabs_icon.svg");
};
class FancyDockingDropZoneState
@@ -323,7 +323,7 @@ namespace AzQtComponents
saturation *= 2.0 - lightness;
}
double value = (lightness + saturation) / 2.0;
saturation = (2.0 * saturation) / (lightness + saturation);
saturation = qFuzzyIsNull(lightness + saturation) ? 0 : (2.0 * saturation) / (lightness + saturation);
m_hsv.saturation = AZ::GetClamp(saturation, 0.0, 1.0);
m_hsv.value = AZ::GetClamp(value, 0.0, 12.5);
@@ -341,11 +341,12 @@ namespace AzQtComponents
double saturation = m_hsv.saturation * m_hsv.value;
if (lightness <= 1.0)
{
saturation /= lightness;
saturation = (qFuzzyIsNull(lightness)) ? 0.0 : saturation / lightness;
}
else
{
saturation /= 2.0 - lightness;
double two_minus_lightness = 2.0 - lightness;
saturation = (qFuzzyIsNull(two_minus_lightness)) ? 0.0 : saturation / two_minus_lightness;
}
lightness /= 2.0;
@@ -164,11 +164,7 @@ namespace
}
}
#if AZ_TRAIT_DISABLE_FAILED_ZERO_COLOR_CONVERSION_TEST
TEST(AzQtComponents, DISABLED_ColorConversionsTestAllZeros)
#else
TEST(AzQtComponents, ColorConversionsTestAllZeros)
#endif // AZ_TRAIT_DISABLE_FAILED_ZERO_COLOR_CONVERSION_TEST
{
TestConversions({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 });
}
@@ -18,12 +18,11 @@
#define AZ_TRAIT_DISABLE_FAILED_ATOM_RPI_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_ZERO_COLOR_CONVERSION_TEST true
#define AZ_TRAIT_DISABLE_FAILED_FRAMEPROFILER_TEST true
#define AZ_TRAIT_DISABLE_FAILED_FRAMEWORK_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_GRADIENT_SIGNAL_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_MULTIPLAYER_GRIDMATE_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_INPUT_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_NATIVE_WINDOWS_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_PROCESS_LAUNCHER_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_TESTS true
@@ -30,6 +30,7 @@
#include <AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h>
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h>
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
#include <AzToolsFramework/Slice/SliceMetadataEntityContextComponent.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponent.h>
@@ -268,6 +269,7 @@ namespace AzToolsFramework
azrtti_typeid<Components::EditorEntityUiSystemComponent>(),
azrtti_typeid<FocusModeSystemComponent>(),
azrtti_typeid<ContainerEntitySystemComponent>(),
azrtti_typeid<ReadOnlyEntitySystemComponent>(),
azrtti_typeid<SliceMetadataEntityContextComponent>(),
azrtti_typeid<Prefab::PrefabSystemComponent>(),
azrtti_typeid<EditorEntityFixupComponent>(),
@@ -23,6 +23,7 @@
#include <AzToolsFramework/Entity/EditorEntityModelComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySearchComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySortComponent.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h>
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
#include <AzToolsFramework/PropertyTreeEditor/PropertyTreeEditorComponent.h>
#include <AzToolsFramework/Render/EditorIntersectorComponent.h>
@@ -75,6 +76,7 @@ namespace AzToolsFramework
EditorEntityFixupComponent::CreateDescriptor(),
EntityUtilityComponent::CreateDescriptor(),
ContainerEntitySystemComponent::CreateDescriptor(),
ReadOnlyEntitySystemComponent::CreateDescriptor(),
FocusModeSystemComponent::CreateDescriptor(),
SliceMetadataEntityContextComponent::CreateDescriptor(),
SliceRequestComponent::CreateDescriptor(),
@@ -0,0 +1,63 @@
/*
* 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
*
*/
#pragma once
#include <AzCore/Component/EntityId.h>
#include <AzCore/EBus/EBus.h>
#include <AzFramework/Entity/EntityContext.h>
namespace AzToolsFramework
{
//! Used to notify changes of state for read-only entities.
class ReadOnlyEntityPublicNotifications
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AzFramework::EntityContextId;
//////////////////////////////////////////////////////////////////////////
//! Triggered when an entity's read-only status changes.
//! @param entityId The entity whose status has changed.
//! @param readOnly The read-only state the container was changed to.
virtual void OnReadOnlyEntityStatusChanged([[maybe_unused]] const AZ::EntityId& entityId, [[maybe_unused]] bool readOnly) {}
protected:
~ReadOnlyEntityPublicNotifications() = default;
};
using ReadOnlyEntityPublicNotificationBus = AZ::EBus<ReadOnlyEntityPublicNotifications>;
//! Used by the ReadOnlyEntitySystemComponent to query the read-only state of entities as set by systems using the API.
class ReadOnlyEntityQueryRequests
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AzFramework::EntityContextId;
//////////////////////////////////////////////////////////////////////////
//! Triggered when an entity's read-only status is queried.
//! Allows multiple systems to weigh in on the read-only status of an entity.
//! @param entityId The entity whose status has changed.
//! @param[out] isReadOnly The output of the query. Should only be changed to true, and left untouched if false.
virtual void IsReadOnly(const AZ::EntityId& entityId, bool& isReadOnly) = 0;
protected:
~ReadOnlyEntityQueryRequests() = default;
};
using ReadOnlyEntityQueryRequestBus = AZ::EBus<ReadOnlyEntityQueryRequests>;
} // namespace AzToolsFramework
@@ -0,0 +1,43 @@
/*
* 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
*
*/
#pragma once
#include <AzCore/Interface/Interface.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Entity/EntityContextBus.h>
namespace AzToolsFramework
{
//! An entity registered as read-only cannot be altered in the editor.
class ReadOnlyEntityPublicInterface
{
public:
AZ_RTTI(ReadOnlyEntityPublicInterface, "{921FE15B-6EBD-47F0-8238-BC63318DEDEA}");
//! Returns whether the entity id provided is registered as read-only.
virtual bool IsReadOnly(const AZ::EntityId& entityId) = 0;
};
//! An entity registered as read-only cannot be altered in the editor.
class ReadOnlyEntityQueryInterface
{
public:
AZ_RTTI(ReadOnlyEntityQueryInterface, "{2ACD63C5-1F3E-4DE8-880E-8115F857D329}");
//! Refreshes the cached read-only status for the entities provided.
//! @param entityIds The entityIds whose read-only state will be queried again.
virtual void RefreshReadOnlyState(const EntityIdList& entityIds) = 0;
//! Refreshes the cached read-only status for all entities.
//! Useful when disconnecting a handler at runtime.
virtual void RefreshReadOnlyStateForAllEntities() = 0;
};
} // namespace AzToolsFramework
@@ -0,0 +1,99 @@
/*
* 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 <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
namespace AzToolsFramework
{
void ReadOnlyEntitySystemComponent::Activate()
{
AZ::Interface<ReadOnlyEntityQueryInterface>::Register(this);
AZ::Interface<ReadOnlyEntityPublicInterface>::Register(this);
EditorEntityContextNotificationBus::Handler::BusConnect();
}
void ReadOnlyEntitySystemComponent::Deactivate()
{
EditorEntityContextNotificationBus::Handler::BusDisconnect();
AZ::Interface<ReadOnlyEntityPublicInterface>::Unregister(this);
AZ::Interface<ReadOnlyEntityQueryInterface>::Unregister(this);
}
void ReadOnlyEntitySystemComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ReadOnlyEntitySystemComponent, AZ::Component>()->Version(1);
}
}
void ReadOnlyEntitySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("ReadOnlyEntityService"));
}
bool ReadOnlyEntitySystemComponent::IsReadOnly(const AZ::EntityId& entityId)
{
if (!m_readOnlystates.contains(entityId))
{
QueryReadOnlyStateForEntity(entityId);
}
return m_readOnlystates[entityId];
}
void ReadOnlyEntitySystemComponent::RefreshReadOnlyState(const EntityIdList& entityIds)
{
for (const AZ::EntityId entityId : entityIds)
{
bool wasReadOnly = m_readOnlystates[entityId];
QueryReadOnlyStateForEntity(entityId);
if (bool isReadOnly = m_readOnlystates[entityId]; wasReadOnly != isReadOnly)
{
ReadOnlyEntityPublicNotificationBus::Broadcast(
&ReadOnlyEntityPublicNotificationBus::Events::OnReadOnlyEntityStatusChanged, entityId, isReadOnly);
}
}
}
void ReadOnlyEntitySystemComponent::RefreshReadOnlyStateForAllEntities()
{
for (auto elem : m_readOnlystates)
{
AZ::EntityId entityId = elem.first;
bool wasReadOnly = m_readOnlystates[entityId];
QueryReadOnlyStateForEntity(entityId);
if (bool isReadOnly = m_readOnlystates[entityId]; wasReadOnly != isReadOnly)
{
ReadOnlyEntityPublicNotificationBus::Broadcast(
&ReadOnlyEntityPublicNotificationBus::Events::OnReadOnlyEntityStatusChanged, entityId, isReadOnly);
}
}
}
void ReadOnlyEntitySystemComponent::OnContextReset()
{
m_readOnlystates.clear();
}
void ReadOnlyEntitySystemComponent::QueryReadOnlyStateForEntity(const AZ::EntityId& entityId)
{
bool isReadOnly = false;
ReadOnlyEntityQueryRequestBus::Broadcast(
&ReadOnlyEntityQueryRequestBus::Events::IsReadOnly, entityId, isReadOnly);
m_readOnlystates[entityId] = isReadOnly;
}
} // namespace AzToolsFramework
@@ -0,0 +1,56 @@
/*
* 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
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityInterface.h>
namespace AzToolsFramework
{
//! System Component to track read-only entity registration.
//! An entity registered as ReadOnly cannot be altered in the Editor.
class ReadOnlyEntitySystemComponent final
: public AZ::Component
, private ReadOnlyEntityPublicInterface
, private ReadOnlyEntityQueryInterface
, private EditorEntityContextNotificationBus::Handler
{
public:
AZ_COMPONENT(ReadOnlyEntitySystemComponent, "{B32EB03F-D88F-4B3A-9C16-071AF04DA646}");
ReadOnlyEntitySystemComponent() = default;
virtual ~ReadOnlyEntitySystemComponent() = default;
// AZ::Component overrides ...
void Activate() override;
void Deactivate() override;
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
// ReadOnlyEntityPublicNotifications overrides ...
bool IsReadOnly(const AZ::EntityId& entityId) override;
// ReadOnlyEntityQueryInterface overrides ...
void RefreshReadOnlyState(const EntityIdList& entityIds) override;
void RefreshReadOnlyStateForAllEntities() override;
// EditorEntityContextNotificationBus overrides ...
void OnContextReset() override;
private:
void QueryReadOnlyStateForEntity(const AZ::EntityId& entityId);
AZStd::unordered_map<AZ::EntityId, bool> m_readOnlystates;
};
} // namespace AzToolsFramework
@@ -14,7 +14,7 @@
namespace AzToolsFramework
{
AZ_CVAR(bool, cl_manipulatorDrawDebug, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enable debug drawing for Manipulators");
AZ_CVAR(bool, ed_manipulatorDrawDebug, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enable debug drawing for Manipulators");
const AZ::Color BaseManipulator::s_defaultMouseOverColor = AZ::Color(1.0f, 1.0f, 0.0f, 1.0f); // yellow
@@ -28,7 +28,7 @@ namespace AzFramework
namespace AzToolsFramework
{
AZ_CVAR_EXTERNED(bool, cl_manipulatorDrawDebug);
AZ_CVAR_EXTERNED(bool, ed_manipulatorDrawDebug);
namespace UndoSystem
{
@@ -207,7 +207,7 @@ namespace AzToolsFramework
? AZ::Transform::CreateFromQuaternionAndTranslation(m_visualOrientationOverride, GetLocalPosition())
: GetLocalTransform();
if (cl_manipulatorDrawDebug)
if (ed_manipulatorDrawDebug)
{
if (PerformingAction())
{
@@ -21,6 +21,7 @@
#include <AzToolsFramework/Manipulators/PlanarManipulator.h>
#include <AzToolsFramework/Manipulators/SplineSelectionManipulator.h>
#include <AzToolsFramework/Maths/TransformUtils.h>
#include <AzToolsFramework/Viewport/ViewportSettings.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
AZ_CVAR(
@@ -30,6 +31,13 @@ AZ_CVAR(
nullptr,
AZ::ConsoleFunctorFlags::Null,
"Display additional debug drawing for manipulator bounds");
AZ_CVAR(
float,
ed_planarManipulatorBoundScaleFactor,
1.75f,
nullptr,
AZ::ConsoleFunctorFlags::Null,
"The scale factor to apply to the planar manipulator bounds");
namespace AzToolsFramework
{
@@ -78,7 +86,8 @@ namespace AzToolsFramework
{
// check if we actually needed to flip the axis, if so, write to shouldCorrect
// so we know and are able to draw it differently if we wish (e.g. hollow if flipped)
const bool correcting = ShouldFlipCameraAxis(worldFromLocal, localPosition, axis, cameraState);
const bool correcting =
FlipManipulatorAxesTowardsView() && ShouldFlipCameraAxis(worldFromLocal, localPosition, axis, cameraState);
// the corrected axis, if no flip was required, output == input
correctedAxis = correcting ? -axis : axis;
@@ -325,7 +334,8 @@ namespace AzToolsFramework
float ManipulatorView::ManipulatorViewScaleMultiplier(
const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState) const
{
return ScreenSizeFixed() ? CalculateScreenToWorldMultiplier(worldPosition, cameraState) : 1.0f;
const float screenScale = ScreenSizeFixed() ? CalculateScreenToWorldMultiplier(worldPosition, cameraState) : 1.0f;
return screenScale * ManipulatorViewBaseScale();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -342,47 +352,77 @@ namespace AzToolsFramework
const AZ::Vector3 axis1 = m_axis1;
const AZ::Vector3 axis2 = m_axis2;
CameraCorrectAxis(
axis1, m_cameraCorrectedAxis1, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState);
CameraCorrectAxis(
axis2, m_cameraCorrectedAxis2, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState);
// support partial application of CameraCorrectAxis to reduce redundant call site parameters
auto cameraCorrectAxisPartialFn =
[&manipulatorState, &managerState, &mouseInteraction, &cameraState](const AZ::Vector3& inAxis, AZ::Vector3& outAxis)
{
CameraCorrectAxis(
inAxis, outAxis, managerState, mouseInteraction, manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition,
cameraState);
};
const Picking::BoundShapeQuad quadBound = CalculateQuadBound(
manipulatorState.m_localPosition, manipulatorState, m_cameraCorrectedAxis1, m_cameraCorrectedAxis2,
m_size *
ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState));
cameraCorrectAxisPartialFn(axis1, m_cameraCorrectedAxis1);
cameraCorrectAxisPartialFn(axis2, m_cameraCorrectedAxis2);
cameraCorrectAxisPartialFn(axis1 * axis1.Dot(m_offset), m_cameraCorrectedOffsetAxis1);
cameraCorrectAxisPartialFn(axis2 * axis2.Dot(m_offset), m_cameraCorrectedOffsetAxis2);
const AZ::Vector3 totalScale =
manipulatorState.m_nonUniformScale * AZ::Vector3(manipulatorState.m_worldFromLocal.GetUniformScale());
const auto cameraCorrectedVisualOffset = (m_cameraCorrectedOffsetAxis1 + m_cameraCorrectedOffsetAxis2) * totalScale.GetReciprocal();
const auto viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const Picking::BoundShapeQuad quadBoundVisual = CalculateQuadBound(
manipulatorState.m_localPosition + (cameraCorrectedVisualOffset * viewScale), manipulatorState, m_cameraCorrectedAxis1,
m_cameraCorrectedAxis2, m_size * viewScale);
debugDisplay.SetLineWidth(defaultLineWidth(manipulatorState.m_mouseOver));
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_axis1Color, m_mouseOverColor).GetAsVector4());
debugDisplay.DrawLine(quadBound.m_corner4, quadBound.m_corner3);
debugDisplay.DrawLine(quadBoundVisual.m_corner4, quadBoundVisual.m_corner3);
debugDisplay.DrawLine(quadBoundVisual.m_corner1, quadBoundVisual.m_corner2);
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_axis2Color, m_mouseOverColor).GetAsVector4());
debugDisplay.DrawLine(quadBound.m_corner2, quadBound.m_corner3);
debugDisplay.DrawLine(quadBoundVisual.m_corner2, quadBoundVisual.m_corner3);
debugDisplay.DrawLine(quadBoundVisual.m_corner1, quadBoundVisual.m_corner4);
if (manipulatorState.m_mouseOver)
{
debugDisplay.SetColor(Vector3ToVector4(m_mouseOverColor.GetAsVector3(), 0.5f));
debugDisplay.CullOff();
debugDisplay.DrawQuad(quadBound.m_corner1, quadBound.m_corner2, quadBound.m_corner3, quadBound.m_corner4);
debugDisplay.DrawQuad(
quadBoundVisual.m_corner1, quadBoundVisual.m_corner2, quadBoundVisual.m_corner3, quadBoundVisual.m_corner4);
debugDisplay.CullOn();
}
RefreshBoundInternal(managerId, manipulatorId, quadBound);
// total size of bounds to use for mouse intersection
const float hitSize = m_size * ed_planarManipulatorBoundScaleFactor;
// size of edge bounds (the 'margin/border' outside the visual representation)
const float edgeSize = (hitSize - m_size) * 0.5f;
const AZ::Vector3 edgeOffset =
((m_cameraCorrectedAxis1 * edgeSize + m_cameraCorrectedAxis2 * edgeSize) * totalScale.GetReciprocal());
const auto cameraCorrectedHitOffset = cameraCorrectedVisualOffset - edgeOffset;
const Picking::BoundShapeQuad quadBoundHit = CalculateQuadBound(
manipulatorState.m_localPosition + (cameraCorrectedHitOffset * viewScale), manipulatorState, m_cameraCorrectedAxis1,
m_cameraCorrectedAxis2, hitSize * viewScale);
if (ed_manipulatorDisplayBoundDebug)
{
debugDisplay.DrawQuad(quadBoundHit.m_corner1, quadBoundHit.m_corner2, quadBoundHit.m_corner3, quadBoundHit.m_corner4);
}
RefreshBoundInternal(managerId, manipulatorId, quadBoundHit);
}
void ManipulatorViewQuadBillboard::Draw(
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
[[maybe_unused]] const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& /*mouseInteraction*/)
[[maybe_unused]] const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const Picking::BoundShapeQuad quadBound = CalculateQuadBoundBillboard(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal,
@@ -442,7 +482,7 @@ namespace AzToolsFramework
void ManipulatorViewLineSelect::Draw(
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
[[maybe_unused]] const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
@@ -570,7 +610,7 @@ namespace AzToolsFramework
void ManipulatorViewSphere::Draw(
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
[[maybe_unused]] const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
@@ -599,12 +639,12 @@ namespace AzToolsFramework
void ManipulatorViewCircle::Draw(
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
[[maybe_unused]] const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& /*mouseInteraction*/)
[[maybe_unused]] const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const float viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
@@ -665,7 +705,7 @@ namespace AzToolsFramework
void ManipulatorViewSplineSelect::Draw(
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
[[maybe_unused]] const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
@@ -698,12 +738,17 @@ namespace AzToolsFramework
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AZStd::unique_ptr<ManipulatorViewQuad> CreateManipulatorViewQuad(
const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const float size)
const PlanarManipulator& planarManipulator,
const AZ::Color& axis1Color,
const AZ::Color& axis2Color,
const AZ::Vector3& offset,
const float size)
{
AZStd::unique_ptr<ManipulatorViewQuad> viewQuad = AZStd::make_unique<ManipulatorViewQuad>();
viewQuad->m_axis1 = planarManipulator.GetAxis1();
viewQuad->m_axis2 = planarManipulator.GetAxis2();
viewQuad->m_size = size;
viewQuad->m_offset = offset;
viewQuad->m_axis1Color = axis1Color;
viewQuad->m_axis2Color = axis2Color;
return viewQuad;
@@ -54,7 +54,7 @@ namespace AzToolsFramework
AZ_RTTI(ManipulatorView, "{7529E3E9-39B3-4D15-899A-FA13770113B2}")
ManipulatorView();
ManipulatorView(bool screenSizeFixed);
explicit ManipulatorView(bool screenSizeFixed);
virtual ~ManipulatorView();
ManipulatorView(ManipulatorView&&) = default;
ManipulatorView& operator=(ManipulatorView&&) = default;
@@ -117,13 +117,16 @@ namespace AzToolsFramework
AZ::Vector3 m_axis1 = AZ::Vector3(1.0f, 0.0f, 0.0f);
AZ::Vector3 m_axis2 = AZ::Vector3(0.0f, 1.0f, 0.0f);
AZ::Vector3 m_offset = AZ::Vector3::CreateZero();
AZ::Color m_axis1Color = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
AZ::Color m_axis2Color = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
float m_size = 0.06f; //!< size to render and do mouse ray intersection tests against.
private:
AZ::Vector3 m_cameraCorrectedAxis1;
AZ::Vector3 m_cameraCorrectedAxis2;
AZ::Vector3 m_cameraCorrectedAxis1; //!< First axis of quad (should be orthogonal to second axis).
AZ::Vector3 m_cameraCorrectedAxis2; //!< Second axis of quad (should be orthogonal to first axis).
AZ::Vector3 m_cameraCorrectedOffsetAxis1; //!< Offset along first axis (parallel with first axis).
AZ::Vector3 m_cameraCorrectedOffsetAxis2; //!< Offset along second axis (parallel with second axis).
};
//! A screen aligned quad, centered at the position of the manipulator, display filled.
@@ -379,7 +382,11 @@ namespace AzToolsFramework
// Helpers to create various manipulator views.
AZStd::unique_ptr<ManipulatorViewQuad> CreateManipulatorViewQuad(
const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color, const AZ::Color& axis2Color, float size);
const PlanarManipulator& planarManipulator,
const AZ::Color& axis1Color,
const AZ::Color& axis2Color,
const AZ::Vector3& offset,
float size);
AZStd::unique_ptr<ManipulatorViewQuadBillboard> CreateManipulatorViewQuadBillboard(const AZ::Color& color, float size);
@@ -132,7 +132,7 @@ namespace AzToolsFramework
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
if (cl_manipulatorDrawDebug)
if (ed_manipulatorDrawDebug)
{
const AZ::Transform combined = TransformUniformScale(GetSpace()) * GetLocalTransform();
for (const auto& fixed : m_fixedAxes)
@@ -171,7 +171,7 @@ namespace AzToolsFramework
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
if (cl_manipulatorDrawDebug)
if (ed_manipulatorDrawDebug)
{
if (PerformingAction())
{
@@ -9,6 +9,7 @@
#include "ScaleManipulators.h"
#include <AzToolsFramework/Maths/TransformUtils.h>
#include <AzToolsFramework/Viewport/ViewportSettings.h>
namespace AzToolsFramework
{
@@ -120,25 +121,25 @@ namespace AzToolsFramework
void ScaleManipulators::ConfigureView(
const float axisLength, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color)
{
const float boxSize = 0.1f;
const float boxHalfExtent = ScaleManipulatorBoxHalfExtent();
const AZ::Color colors[] = { axis1Color, axis2Color, axis3Color };
for (size_t manipulatorIndex = 0; manipulatorIndex < m_axisScaleManipulators.size(); ++manipulatorIndex)
{
const auto lineLength = axisLength - boxSize;
const auto lineLength = axisLength - (2.0f * boxHalfExtent);
ManipulatorViews views;
views.emplace_back(
CreateManipulatorViewLine(*m_axisScaleManipulators[manipulatorIndex], colors[manipulatorIndex], axisLength, m_lineBoundWidth));
views.emplace_back(CreateManipulatorViewLine(
*m_axisScaleManipulators[manipulatorIndex], colors[manipulatorIndex], axisLength, m_lineBoundWidth));
views.emplace_back(CreateManipulatorViewBox(
AZ::Transform::CreateIdentity(), colors[manipulatorIndex],
m_axisScaleManipulators[manipulatorIndex]->GetAxis() * lineLength, AZ::Vector3(boxSize)));
m_axisScaleManipulators[manipulatorIndex]->GetAxis() * (lineLength + boxHalfExtent), AZ::Vector3(boxHalfExtent)));
m_axisScaleManipulators[manipulatorIndex]->SetViews(AZStd::move(views));
}
ManipulatorViews views;
views.emplace_back(CreateManipulatorViewBox(
AZ::Transform::CreateIdentity(), AZ::Color::CreateOne(), AZ::Vector3::CreateZero(), AZ::Vector3(boxSize)));
AZ::Transform::CreateIdentity(), AZ::Color::CreateOne(), AZ::Vector3::CreateZero(), AZ::Vector3(boxHalfExtent)));
m_uniformScaleManipulator->SetViews(AZStd::move(views));
}
@@ -10,13 +10,10 @@
#include <AzCore/Math/VectorConversions.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <AzToolsFramework/Viewport/ViewportSettings.h>
namespace AzToolsFramework
{
static const float SurfaceManipulatorTransparency = 0.75f;
static const float LinearManipulatorAxisLength = 2.0f;
static const float SurfaceManipulatorRadius = 0.1f;
static const AZ::Color LinearManipulatorXAxisColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
static const AZ::Color LinearManipulatorYAxisColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
static const AZ::Color LinearManipulatorZAxisColor = AZ::Color(0.0f, 0.0f, 1.0f, 1.0f);
@@ -240,18 +237,16 @@ namespace AzToolsFramework
const AZ::Color& axis2Color,
const AZ::Color& axis3Color /*= AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)*/)
{
const float coneLength = 0.28f;
const float coneRadius = 0.07f;
const AZ::Color axesColor[] = { axis1Color, axis2Color, axis3Color };
const auto configureLinearView = [lineBoundWidth = m_lineBoundWidth, coneLength, axisLength,
coneRadius](LinearManipulator* linearManipulator, const AZ::Color& color)
const auto configureLinearView =
[lineBoundWidth = m_lineBoundWidth, coneLength = LinearManipulatorConeLength(), axisLength,
coneRadius = LinearManipulatorConeRadius()](LinearManipulator* linearManipulator, const AZ::Color& color)
{
const auto lineLength = axisLength - coneLength;
ManipulatorViews views;
views.emplace_back(CreateManipulatorViewLine(*linearManipulator, color, lineLength, lineBoundWidth));
views.emplace_back(CreateManipulatorViewLine(*linearManipulator, color, axisLength, lineBoundWidth));
views.emplace_back(
CreateManipulatorViewCone(*linearManipulator, color, linearManipulator->GetAxis() * lineLength, coneLength, coneRadius));
linearManipulator->SetViews(AZStd::move(views));
@@ -264,17 +259,23 @@ namespace AzToolsFramework
}
void TranslationManipulators::ConfigurePlanarView(
const float planeSize,
const AZ::Color& plane1Color,
const AZ::Color& plane2Color /*= AZ::Color(0.0f, 1.0f, 0.0f, 0.5f)*/,
const AZ::Color& plane3Color /*= AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)*/)
{
const float planeSize = 0.6f;
const AZ::Color planesColor[] = { plane1Color, plane2Color, plane3Color };
const float linearAxisLength = LinearManipulatorAxisLength();
const float linearConeLength = LinearManipulatorConeLength();
for (size_t manipulatorIndex = 0; manipulatorIndex < m_planarManipulators.size(); ++manipulatorIndex)
{
const auto& planarManipulator = *m_planarManipulators[manipulatorIndex];
const AZStd::shared_ptr<ManipulatorViewQuad> manipulatorView = CreateManipulatorViewQuad(
*m_planarManipulators[manipulatorIndex], planesColor[manipulatorIndex], planesColor[(manipulatorIndex + 1) % 3], planeSize);
*m_planarManipulators[manipulatorIndex], planesColor[manipulatorIndex], planesColor[(manipulatorIndex + 1) % 3],
(planarManipulator.GetAxis1() + planarManipulator.GetAxis2()) *
(((linearAxisLength - linearConeLength) * 0.5f) - (planeSize * 0.5f)),
planeSize);
m_planarManipulators[manipulatorIndex]->SetViews(ManipulatorViews{ manipulatorView });
}
@@ -286,12 +287,11 @@ namespace AzToolsFramework
{
m_surfaceManipulator->SetView(CreateManipulatorViewSphere(
color, radius,
[](const ViewportInteraction::MouseInteraction& /*mouseInteraction*/, bool mouseOver,
[]([[maybe_unused]] const ViewportInteraction::MouseInteraction& mouseInteraction, bool mouseOver,
const AZ::Color& defaultColor) -> AZ::Color
{
const AZ::Color color[2] = {
defaultColor,
Vector3ToVector4(BaseManipulator::s_defaultMouseOverColor.GetAsVector3(), SurfaceManipulatorTransparency)
defaultColor, Vector3ToVector4(BaseManipulator::s_defaultMouseOverColor.GetAsVector3(), SurfaceManipulatorOpacity())
};
return color[mouseOver];
@@ -325,16 +325,19 @@ namespace AzToolsFramework
void ConfigureTranslationManipulatorAppearance3d(TranslationManipulators* translationManipulators)
{
translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
translationManipulators->ConfigurePlanarView(LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor);
translationManipulators->ConfigurePlanarView(
PlanarManipulatorAxisLength(), LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor);
translationManipulators->ConfigureLinearView(
LinearManipulatorAxisLength, LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor);
translationManipulators->ConfigureSurfaceView(SurfaceManipulatorRadius, SurfaceManipulatorColor);
LinearManipulatorAxisLength(), LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor);
translationManipulators->ConfigureSurfaceView(SurfaceManipulatorRadius(), SurfaceManipulatorColor);
}
void ConfigureTranslationManipulatorAppearance2d(TranslationManipulators* translationManipulators)
{
translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY());
translationManipulators->ConfigurePlanarView(LinearManipulatorXAxisColor);
translationManipulators->ConfigureLinearView(LinearManipulatorAxisLength, LinearManipulatorXAxisColor, LinearManipulatorYAxisColor);
translationManipulators->ConfigurePlanarView(
PlanarManipulatorAxisLength(), LinearManipulatorXAxisColor, LinearManipulatorYAxisColor);
translationManipulators->ConfigureLinearView(
LinearManipulatorAxisLength(), LinearManipulatorXAxisColor, LinearManipulatorYAxisColor);
}
} // namespace AzToolsFramework
@@ -53,6 +53,7 @@ namespace AzToolsFramework
void SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3 = AZ::Vector3::CreateAxisZ());
void ConfigurePlanarView(
float planeSize,
const AZ::Color& plane1Color,
const AZ::Color& plane2Color = AZ::Color(0.0f, 1.0f, 0.0f, 0.5f),
const AZ::Color& plane3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f));
@@ -521,21 +521,18 @@ namespace AzToolsFramework
nestedInstanceLink.has_value(),
"A valid link was not found for one of the instances provided as input for the CreatePrefab operation.");
PrefabDomReference nestedInstanceLinkDom = nestedInstanceLink->get().GetLinkDom();
AZ_Assert(
nestedInstanceLinkDom.has_value(),
"A valid DOM was not found for the link corresponding to one of the instances provided as input for the "
"CreatePrefab operation.");
PrefabDomValueReference nestedInstanceLinkPatches =
PrefabDomUtils::FindPrefabDomValue(nestedInstanceLinkDom->get(), PrefabDomUtils::PatchesName);
AZ_Assert(
nestedInstanceLinkPatches.has_value(),
"A valid DOM for patches was not found for the link corresponding to one of the instances provided as input for the "
"CreatePrefab operation.");
PrefabDom patchesCopyForUndoSupport;
patchesCopyForUndoSupport.CopyFrom(nestedInstanceLinkPatches->get(), patchesCopyForUndoSupport.GetAllocator());
PrefabDomReference nestedInstanceLinkDom = nestedInstanceLink->get().GetLinkDom();
if (nestedInstanceLinkDom.has_value())
{
PrefabDomValueReference nestedInstanceLinkPatches =
PrefabDomUtils::FindPrefabDomValue(nestedInstanceLinkDom->get(), PrefabDomUtils::PatchesName);
if (nestedInstanceLinkPatches.has_value())
{
patchesCopyForUndoSupport.CopyFrom(nestedInstanceLinkPatches->get(), patchesCopyForUndoSupport.GetAllocator());
}
}
PrefabUndoHelpers::RemoveLink(
sourceInstance->GetTemplateId(), targetTemplateId, sourceInstance->GetInstanceAlias(), sourceInstance->GetLinkId(),
AZStd::move(patchesCopyForUndoSupport), undoBatch);
@@ -0,0 +1,123 @@
/*
* 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 <AzToolsFramework/Viewport/ViewportSettings.h>
namespace AzToolsFramework
{
constexpr AZStd::string_view FlipManipulatorAxesTowardsViewSetting = "/Amazon/Preferences/Editor/Manipulator/FlipManipulatorAxesTowardsView";
constexpr AZStd::string_view LinearManipulatorAxisLengthSetting = "/Amazon/Preferences/Editor/Manipulator/LinearManipulatorAxisLength";
constexpr AZStd::string_view PlanarManipulatorAxisLengthSetting = "/Amazon/Preferences/Editor/Manipulator/PlanarManipulatorAxisLength";
constexpr AZStd::string_view SurfaceManipulatorRadiusSetting = "/Amazon/Preferences/Editor/Manipulator/SurfaceManipulatorRadius";
constexpr AZStd::string_view SurfaceManipulatorOpacitySetting = "/Amazon/Preferences/Editor/Manipulator/SurfaceManipulatorOpacity";
constexpr AZStd::string_view LinearManipulatorConeLengthSetting = "/Amazon/Preferences/Editor/Manipulator/LinearManipulatorConeLength";
constexpr AZStd::string_view LinearManipulatorConeRadiusSetting = "/Amazon/Preferences/Editor/Manipulator/LinearManipulatorConeRadius";
constexpr AZStd::string_view ScaleManipulatorBoxHalfExtentSetting = "/Amazon/Preferences/Editor/Manipulator/ScaleManipulatorBoxHalfExtent";
constexpr AZStd::string_view RotationManipulatorRadiusSetting = "/Amazon/Preferences/Editor/Manipulator/RotationManipulatorRadius";
constexpr AZStd::string_view ManipulatorViewBaseScaleSetting = "/Amazon/Preferences/Editor/Manipulator/ViewBaseScale";
bool FlipManipulatorAxesTowardsView()
{
return GetRegistry(FlipManipulatorAxesTowardsViewSetting, true);
}
void SetFlipManipulatorAxesTowardsView(const bool enabled)
{
SetRegistry(FlipManipulatorAxesTowardsViewSetting, enabled);
}
float LinearManipulatorAxisLength()
{
return aznumeric_cast<float>(GetRegistry(LinearManipulatorAxisLengthSetting, 2.0));
}
void SetLinearManipulatorAxisLength(const float length)
{
SetRegistry(LinearManipulatorAxisLengthSetting, length);
}
float PlanarManipulatorAxisLength()
{
return aznumeric_cast<float>(GetRegistry(PlanarManipulatorAxisLengthSetting, 0.6));
}
void SetPlanarManipulatorAxisLength(const float length)
{
SetRegistry(PlanarManipulatorAxisLengthSetting, length);
}
float SurfaceManipulatorRadius()
{
return aznumeric_cast<float>(GetRegistry(SurfaceManipulatorRadiusSetting, 0.1));
}
void SetSurfaceManipulatorRadius(const float radius)
{
SetRegistry(SurfaceManipulatorRadiusSetting, radius);
}
float SurfaceManipulatorOpacity()
{
return aznumeric_cast<float>(GetRegistry(SurfaceManipulatorOpacitySetting, 0.75));
}
void SetSurfaceManipulatorOpacity(const float opacity)
{
SetRegistry(SurfaceManipulatorOpacitySetting, opacity);
}
float LinearManipulatorConeLength()
{
return aznumeric_cast<float>(GetRegistry(LinearManipulatorConeLengthSetting, 0.28));
}
void SetLinearManipulatorConeLength(const float length)
{
SetRegistry(LinearManipulatorConeLengthSetting, length);
}
float LinearManipulatorConeRadius()
{
return aznumeric_cast<float>(GetRegistry(LinearManipulatorConeRadiusSetting, 0.1));
}
void SetLinearManipulatorConeRadius(const float radius)
{
SetRegistry(LinearManipulatorConeRadiusSetting, radius);
}
float ScaleManipulatorBoxHalfExtent()
{
return aznumeric_cast<float>(GetRegistry(ScaleManipulatorBoxHalfExtentSetting, 0.1));
}
void SetScaleManipulatorBoxHalfExtent(const float size)
{
SetRegistry(ScaleManipulatorBoxHalfExtentSetting, size);
}
float RotationManipulatorRadius()
{
return aznumeric_cast<float>(GetRegistry(RotationManipulatorRadiusSetting, 2.0));
}
void SetRotationManipulatorRadius(const float radius)
{
SetRegistry(RotationManipulatorRadiusSetting, radius);
}
float ManipulatorViewBaseScale()
{
return aznumeric_cast<float>(GetRegistry(ManipulatorViewBaseScaleSetting, 1.0));
}
void SetManipulatorViewBaseScale(const float scale)
{
SetRegistry(ManipulatorViewBaseScaleSetting, scale);
}
} // namespace AzToolsFramework
@@ -0,0 +1,69 @@
/*
* 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
*
*/
#pragma once
#include <AzCore/Settings/SettingsRegistry.h>
namespace AzToolsFramework
{
template<typename T>
void SetRegistry(const AZStd::string_view setting, T&& value)
{
if (auto* registry = AZ::SettingsRegistry::Get())
{
registry->Set(setting, AZStd::forward<T>(value));
}
}
template<typename T>
AZStd::remove_cvref_t<T> GetRegistry(const AZStd::string_view setting, T&& defaultValue)
{
AZStd::remove_cvref_t<T> value = AZStd::forward<T>(defaultValue);
if (const auto* registry = AZ::SettingsRegistry::Get())
{
T potentialValue;
if (registry->Get(potentialValue, setting))
{
value = AZStd::move(potentialValue);
}
}
return value;
}
bool FlipManipulatorAxesTowardsView();
void SetFlipManipulatorAxesTowardsView(bool enabled);
float LinearManipulatorAxisLength();
void SetLinearManipulatorAxisLength(float length);
float PlanarManipulatorAxisLength();
void SetPlanarManipulatorAxisLength(float length);
float SurfaceManipulatorRadius();
void SetSurfaceManipulatorRadius(float radius);
float SurfaceManipulatorOpacity();
void SetSurfaceManipulatorOpacity(float opacity);
float LinearManipulatorConeLength();
void SetLinearManipulatorConeLength(float length);
float LinearManipulatorConeRadius();
void SetLinearManipulatorConeRadius(float radius);
float ScaleManipulatorBoxHalfExtent();
void SetScaleManipulatorBoxHalfExtent(float halfExtent);
float RotationManipulatorRadius();
void SetRotationManipulatorRadius(float radius);
float ManipulatorViewBaseScale();
void SetManipulatorViewBaseScale(float scale);
} // namespace AzToolsFramework
@@ -33,6 +33,7 @@
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <AzToolsFramework/Viewport/ActionBus.h>
#include <AzToolsFramework/Viewport/ViewportSettings.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
#include <Entity/EditorEntityContextBus.h>
@@ -1376,7 +1377,7 @@ namespace AzToolsFramework
// view
rotationManipulators->SetLocalAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
rotationManipulators->ConfigureView(
2.0f, AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor,
RotationManipulatorRadius(), AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor,
AzFramework::ViewportColors::ZAxisColor);
struct SharedRotationState
@@ -1535,7 +1536,8 @@ namespace AzToolsFramework
RecalculateAverageManipulatorTransform(m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame));
scaleManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
scaleManipulators->ConfigureView(2.0f, AZ::Color::CreateOne(), AZ::Color::CreateOne(), AZ::Color::CreateOne());
scaleManipulators->ConfigureView(
LinearManipulatorAxisLength(), AZ::Color::CreateOne(), AZ::Color::CreateOne(), AZ::Color::CreateOne());
struct SharedScaleState
{
@@ -159,6 +159,10 @@ set(FILES
Entity/SliceEditorEntityOwnershipServiceBus.h
Entity/EntityUtilityComponent.h
Entity/EntityUtilityComponent.cpp
Entity/ReadOnly/ReadOnlyEntityInterface.h
Entity/ReadOnly/ReadOnlyEntityBus.h
Entity/ReadOnly/ReadOnlyEntitySystemComponent.cpp
Entity/ReadOnly/ReadOnlyEntitySystemComponent.h
Fingerprinting/TypeFingerprinter.h
Fingerprinting/TypeFingerprinter.cpp
FocusMode/FocusModeInterface.h
@@ -502,6 +506,8 @@ set(FILES
Viewport/ViewportMessages.cpp
Viewport/ViewportTypes.h
Viewport/ViewportTypes.cpp
Viewport/ViewportSettings.h
Viewport/ViewportSettings.cpp
ViewportUi/Button.h
ViewportUi/Button.cpp
ViewportUi/ButtonGroup.h
@@ -0,0 +1,125 @@
/*
* 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 <Tests/Entity/ReadOnly/ReadOnlyEntityFixture.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
namespace AzToolsFramework
{
void ReadOnlyEntityFixture::SetUpEditorFixtureImpl()
{
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
m_readOnlyEntityPublicInterface = AZ::Interface<ReadOnlyEntityPublicInterface>::Get();
ASSERT_TRUE(m_readOnlyEntityPublicInterface != nullptr);
GenerateTestHierarchy();
}
void ReadOnlyEntityFixture::TearDownEditorFixtureImpl()
{
}
void ReadOnlyEntityFixture::GenerateTestHierarchy()
{
/*
* Root
* |_ Child
* |_ GrandChild1
* |_ GrandChild2
*/
m_entityMap[RootEntityName] = CreateEditorEntity(RootEntityName, AZ::EntityId());
m_entityMap[ChildEntityName] = CreateEditorEntity(ChildEntityName, m_entityMap[RootEntityName]);
m_entityMap[GrandChild1EntityName] = CreateEditorEntity(GrandChild1EntityName, m_entityMap[ChildEntityName]);
m_entityMap[GrandChild2EntityName] = CreateEditorEntity(GrandChild2EntityName, m_entityMap[ChildEntityName]);
}
AZ::EntityId ReadOnlyEntityFixture::CreateEditorEntity(const char* name, AZ::EntityId parentId)
{
AZ::Entity* entity = nullptr;
UnitTest::CreateDefaultEditorEntity(name, &entity);
// Parent
AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId);
return entity->GetId();
}
ReadOnlyHandlerAlwaysTrue::ReadOnlyHandlerAlwaysTrue()
{
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
ReadOnlyEntityQueryRequestBus::Handler::BusConnect(editorEntityContextId);
}
ReadOnlyHandlerAlwaysTrue::~ReadOnlyHandlerAlwaysTrue()
{
ReadOnlyEntityQueryRequestBus::Handler::BusDisconnect();
if (auto readOnlyEntityQueryInterface = AZ::Interface<ReadOnlyEntityQueryInterface>::Get())
{
readOnlyEntityQueryInterface->RefreshReadOnlyStateForAllEntities();
}
}
void ReadOnlyHandlerAlwaysTrue::IsReadOnly([[maybe_unused]] const AZ::EntityId& entityId, bool& isReadOnly)
{
isReadOnly = true;
}
ReadOnlyHandlerAlwaysFalse::ReadOnlyHandlerAlwaysFalse()
{
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
ReadOnlyEntityQueryRequestBus::Handler::BusConnect(editorEntityContextId);
}
ReadOnlyHandlerAlwaysFalse::~ReadOnlyHandlerAlwaysFalse()
{
ReadOnlyEntityQueryRequestBus::Handler::BusDisconnect();
if (auto readOnlyEntityQueryInterface = AZ::Interface<ReadOnlyEntityQueryInterface>::Get())
{
readOnlyEntityQueryInterface->RefreshReadOnlyStateForAllEntities();
}
}
ReadOnlyHandlerEntityId::ReadOnlyHandlerEntityId(AZ::EntityId entityId)
: m_entityId(entityId)
{
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
ReadOnlyEntityQueryRequestBus::Handler::BusConnect(editorEntityContextId);
}
ReadOnlyHandlerEntityId::~ReadOnlyHandlerEntityId()
{
ReadOnlyEntityQueryRequestBus::Handler::BusDisconnect();
if (auto readOnlyEntityQueryInterface = AZ::Interface<ReadOnlyEntityQueryInterface>::Get())
{
readOnlyEntityQueryInterface->RefreshReadOnlyStateForAllEntities();
}
}
void ReadOnlyHandlerEntityId::IsReadOnly(const AZ::EntityId& entityId, bool& isReadOnly)
{
if (entityId == m_entityId)
{
isReadOnly = true;
}
}
}
@@ -0,0 +1,78 @@
/*
* 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
*
*/
#pragma once
#include <AzCore/Component/TransformBus.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityBus.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityInterface.h>
namespace AzToolsFramework
{
class ReadOnlyEntityFixture
: public UnitTest::ToolsApplicationFixture
{
protected:
void SetUpEditorFixtureImpl() override;
void TearDownEditorFixtureImpl() override;
void GenerateTestHierarchy();
AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId);
AZStd::unordered_map<AZStd::string, AZ::EntityId> m_entityMap;
ReadOnlyEntityPublicInterface* m_readOnlyEntityPublicInterface = nullptr;
public:
inline static const char* RootEntityName = "Root";
inline static const char* ChildEntityName = "Child";
inline static const char* GrandChild1EntityName = "GrandChild1";
inline static const char* GrandChild2EntityName = "GrandChild2";
};
class ReadOnlyHandlerAlwaysTrue
: public ReadOnlyEntityQueryRequestBus::Handler
{
public:
ReadOnlyHandlerAlwaysTrue();
~ReadOnlyHandlerAlwaysTrue();
// ReadOnlyEntityQueryNotificationBus overrides ...
void IsReadOnly(const AZ::EntityId& entityId, bool& isReadOnly) override;
};
class ReadOnlyHandlerAlwaysFalse
: public ReadOnlyEntityQueryRequestBus::Handler
{
public:
ReadOnlyHandlerAlwaysFalse();
~ReadOnlyHandlerAlwaysFalse();
// ReadOnlyEntityQueryNotificationBus overrides ...
void IsReadOnly([[maybe_unused]] const AZ::EntityId& entityId, [[maybe_unused]] bool& isReadOnly) override {}
};
class ReadOnlyHandlerEntityId
: public ReadOnlyEntityQueryRequestBus::Handler
{
public:
ReadOnlyHandlerEntityId(AZ::EntityId entityId);
~ReadOnlyHandlerEntityId();
// ReadOnlyEntityQueryNotificationBus overrides ...
void IsReadOnly(const AZ::EntityId& entityId, bool& isReadOnly) override;
private:
AZ::EntityId m_entityId;
};
}
@@ -0,0 +1,99 @@
/*
* 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 <Tests/Entity/ReadOnly/ReadOnlyEntityFixture.h>
namespace AzToolsFramework
{
TEST_F(ReadOnlyEntityFixture, NoHandlerEntityIsNotReadOnlyByDefault)
{
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName]));
}
TEST_F(ReadOnlyEntityFixture, SingleHandlerEntityIsReadOnly)
{
// Create a handler that sets all entities to read-only.
ReadOnlyHandlerAlwaysTrue alwaysTrueHandler;
// All entities should be marked read-only now.
EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[RootEntityName]));
EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName]));
EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[GrandChild1EntityName]));
EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[GrandChild2EntityName]));
}
TEST_F(ReadOnlyEntityFixture, SingleHandlerEntityIsNotReadOnly)
{
// Create a handler that sets all entities to read-only.
ReadOnlyHandlerAlwaysFalse alwaysFalseHandler;
// All entities should not be marked read-only now.
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[RootEntityName]));
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName]));
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[GrandChild1EntityName]));
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[GrandChild2EntityName]));
}
TEST_F(ReadOnlyEntityFixture, SingleHandlerWithLogic)
{
// Create a handler that sets just the child entity to read-only.
ReadOnlyHandlerEntityId entityIdHandler(m_entityMap[ChildEntityName]);
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[RootEntityName]));
EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName]));
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[GrandChild1EntityName]));
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[GrandChild2EntityName]));
}
TEST_F(ReadOnlyEntityFixture, TwoHandlersCanOverlap)
{
// Create two handlers that set different entities to read-only.
ReadOnlyHandlerEntityId entityIdHandler1(m_entityMap[ChildEntityName]);
ReadOnlyHandlerEntityId entityIdHandler2(m_entityMap[GrandChild2EntityName]);
// Both entities should be marked as read-only, while others aren't.
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[RootEntityName]));
EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName]));
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[GrandChild1EntityName]));
EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[GrandChild2EntityName]));
}
TEST_F(ReadOnlyEntityFixture, EnsureCacheIsRefreshedCorrectly)
{
// Verify the child entity is not marked as read-only
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName]));
// Create a handler that sets the child entity to read-only.
ReadOnlyHandlerEntityId entityIdHandler(m_entityMap[ChildEntityName]);
// Communicate to the ReadOnlyEntitySystemComponent that the read-only state for the child entity may have changed.
// Note that this operation would usually be executed by the handler, hence the Query interface call.
if (auto readOnlyEntityQueryInterface = AZ::Interface<ReadOnlyEntityQueryInterface>::Get())
{
readOnlyEntityQueryInterface->RefreshReadOnlyState({ m_entityMap[ChildEntityName] });
}
// Verify the child entity is marked as read-only
EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName]));
}
TEST_F(ReadOnlyEntityFixture, EnsureCacheIsClearedCorrectly)
{
{
// Create a handler that sets the child entity to read-only.
ReadOnlyHandlerEntityId entityIdHandler(m_entityMap[ChildEntityName]);
// Verify the child entity is marked as read-only
EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName]));
}
// When the handler goes out of scope, it calls RefreshReadOnlyStateForAllEntities and refreshes the cache.
// Verify the child entity is no longer marked as read-only
EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName]));
}
}
@@ -0,0 +1,150 @@
/*
* 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/Settings/SettingsRegistryMergeUtils.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <Prefab/PrefabTestComponent.h>
#include <Prefab/PrefabTestDomUtils.h>
#include <Prefab/PrefabTestFixture.h>
namespace UnitTest
{
using PrefabDeleteTest = PrefabTestFixture;
TEST_F(PrefabDeleteTest, DeleteEntitiesInInstance_DeleteSingleEntitySucceeds)
{
PrefabEntityResult createEntityResult = m_prefabPublicInterface->CreateEntity(AZ::EntityId(), AZ::Vector3());
// Verify that a valid entity is created.
AZ::EntityId testEntityId = createEntityResult.GetValue();
ASSERT_TRUE(testEntityId.IsValid());
AZ::Entity* testEntity = AzToolsFramework::GetEntityById(testEntityId);
ASSERT_TRUE(testEntity != nullptr);
m_prefabPublicInterface->DeleteEntitiesInInstance(AzToolsFramework::EntityIdList{ testEntityId });
// Verify that entity can't be found after deletion.
testEntity = AzToolsFramework::GetEntityById(testEntityId);
EXPECT_TRUE(testEntity == nullptr);
}
TEST_F(PrefabDeleteTest, DeleteEntitiesInInstance_DeleteSinglePrefabSucceeds)
{
PrefabEntityResult createEntityResult = m_prefabPublicInterface->CreateEntity(AZ::EntityId(), AZ::Vector3());
// Verify that a valid entity is created.
AZ::EntityId createdEntityId = createEntityResult.GetValue();
ASSERT_TRUE(createdEntityId.IsValid());
AZ::Entity* createdEntity = AzToolsFramework::GetEntityById(createdEntityId);
ASSERT_TRUE(createdEntity != nullptr);
// Rather than hardcode a path, use a path from settings registry since that will work on all platforms.
AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
AZ::IO::FixedMaxPath path;
registry->Get(path.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
CreatePrefabResult createPrefabResult =
m_prefabPublicInterface->CreatePrefabInMemory(AzToolsFramework::EntityIdList{ createdEntityId }, path);
AZ::EntityId createdPrefabContainerId = createPrefabResult.GetValue();
ASSERT_TRUE(createdPrefabContainerId.IsValid());
AZ::Entity* prefabContainerEntity = AzToolsFramework::GetEntityById(createdPrefabContainerId);
ASSERT_TRUE(prefabContainerEntity != nullptr);
// Verify that the prefab container entity and the entity within are deleted.
m_prefabPublicInterface->DeleteEntitiesInInstance(AzToolsFramework::EntityIdList{ createdPrefabContainerId });
prefabContainerEntity = AzToolsFramework::GetEntityById(createdPrefabContainerId);
EXPECT_TRUE(prefabContainerEntity == nullptr);
createdEntity = AzToolsFramework::GetEntityById(createdEntityId);
EXPECT_TRUE(createdEntity == nullptr);
}
TEST_F(PrefabDeleteTest, DeleteEntitiesAndAllDescendantsInInstance_DeletingEntityDeletesChildEntityToo)
{
PrefabEntityResult parentEntityCreationResult = m_prefabPublicInterface->CreateEntity(AZ::EntityId(), AZ::Vector3());
// Verify that valid parent entity is created.
AZ::EntityId parentEntityId = parentEntityCreationResult.GetValue();
ASSERT_TRUE(parentEntityId.IsValid());
AZ::Entity* parentEntity = AzToolsFramework::GetEntityById(parentEntityId);
ASSERT_TRUE(parentEntity != nullptr);
// Verify that valid child entity is created.
PrefabEntityResult childEntityCreationResult = m_prefabPublicInterface->CreateEntity(parentEntityId, AZ::Vector3());
AZ::EntityId childEntityId = childEntityCreationResult.GetValue();
ASSERT_TRUE(childEntityId.IsValid());
AZ::Entity* childEntity = AzToolsFramework::GetEntityById(childEntityId);
ASSERT_TRUE(childEntity != nullptr);
// PrefabTestFixture won't add required editor components by default. Hence we add them here.
AddRequiredEditorComponents(childEntity);
AddRequiredEditorComponents(parentEntity);
// Parent the child entity under the parent entity.
AZ::TransformBus::Event(childEntityId, &AZ::TransformBus::Events::SetParent, parentEntityId);
// Delete parent entity and its children.
m_prefabPublicInterface->DeleteEntitiesAndAllDescendantsInInstance(AzToolsFramework::EntityIdList{ parentEntityId });
// Verify that both the parent and child entities are deleted.
parentEntity = AzToolsFramework::GetEntityById(parentEntityId);
EXPECT_TRUE(parentEntity == nullptr);
childEntity = AzToolsFramework::GetEntityById(childEntityId);
EXPECT_TRUE(childEntity == nullptr);
}
TEST_F(PrefabDeleteTest, DeleteEntitiesAndAllDescendantsInInstance_DeletingEntityDeletesChildPrefabToo)
{
PrefabEntityResult entityToBePutUnderPrefabResult = m_prefabPublicInterface->CreateEntity(AZ::EntityId(), AZ::Vector3());
// Verify that a valid entity is created that will be put in a prefab later.
AZ::EntityId entityToBePutUnderPrefabId = entityToBePutUnderPrefabResult.GetValue();
ASSERT_TRUE(entityToBePutUnderPrefabId.IsValid());
AZ::Entity* entityToBePutUnderPrefab = AzToolsFramework::GetEntityById(entityToBePutUnderPrefabId);
ASSERT_TRUE(entityToBePutUnderPrefab != nullptr);
// Verify that a valid parent entity is created.
PrefabEntityResult parentEntityCreationResult = m_prefabPublicInterface->CreateEntity(AZ::EntityId(), AZ::Vector3());
AZ::EntityId parentEntityId = parentEntityCreationResult.GetValue();
ASSERT_TRUE(parentEntityId.IsValid());
AZ::Entity* parentEntity = AzToolsFramework::GetEntityById(parentEntityId);
ASSERT_TRUE(parentEntity != nullptr);
// Rather than hardcode a path, use a path from settings registry since that will work on all platforms.
AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
AZ::IO::FixedMaxPath path;
registry->Get(path.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
CreatePrefabResult createPrefabResult =
m_prefabPublicInterface->CreatePrefabInMemory(AzToolsFramework::EntityIdList{ entityToBePutUnderPrefabId }, path);
// Verify that a valid prefab container entity is created.
AZ::EntityId createdPrefabContainerId = createPrefabResult.GetValue();
ASSERT_TRUE(createdPrefabContainerId.IsValid());
AZ::Entity* prefabContainerEntity = AzToolsFramework::GetEntityById(createdPrefabContainerId);
ASSERT_TRUE(prefabContainerEntity != nullptr);
// PrefabTestFixture won't add required editor components by default. Hence we add them here.
AddRequiredEditorComponents(parentEntity);
AddRequiredEditorComponents(prefabContainerEntity);
// Parent the prefab under the parent entity.
AZ::TransformBus::Event(createdPrefabContainerId, &AZ::TransformBus::Events::SetParent, parentEntityId);
// Delete the parent entity.
m_prefabPublicInterface->DeleteEntitiesAndAllDescendantsInInstance(AzToolsFramework::EntityIdList{ parentEntityId });
// Validate that the parent and the prefab under it and the entity inside the prefab are all deleted.
parentEntity = AzToolsFramework::GetEntityById(parentEntityId);
ASSERT_TRUE(parentEntity == nullptr);
entityToBePutUnderPrefab = AzToolsFramework::GetEntityById(entityToBePutUnderPrefabId);
ASSERT_TRUE(entityToBePutUnderPrefab == nullptr);
prefabContainerEntity = AzToolsFramework::GetEntityById(createdPrefabContainerId);
EXPECT_TRUE(prefabContainerEntity == nullptr);
}
} // namespace UnitTest
@@ -57,6 +57,11 @@ namespace UnitTest
return AZStd::make_unique<PrefabTestToolsApplication>("PrefabTestApplication");
}
void PrefabTestFixture::PropagateAllTemplateChanges()
{
m_prefabSystemComponent->OnSystemTick();
}
AZ::Entity* PrefabTestFixture::CreateEntity(const char* entityName, const bool shouldActivate)
{
// Circumvent the EntityContext system and generate a new entity with a transformcomponent
@@ -125,4 +130,13 @@ namespace UnitTest
EXPECT_EQ(entityInInstance->GetState(), AZ::Entity::State::Active);
}
}
void PrefabTestFixture::AddRequiredEditorComponents(AZ::Entity* entity)
{
ASSERT_TRUE(entity != nullptr);
entity->Deactivate();
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
&AzToolsFramework::EditorEntityContextRequests::AddRequiredComponents, *entity);
entity->Activate();
}
}
@@ -52,6 +52,8 @@ namespace UnitTest
AZStd::unique_ptr<ToolsTestApplication> CreateTestApplication() override;
void PropagateAllTemplateChanges();
AZ::Entity* CreateEntity(const char* entityName, const bool shouldActivate = true);
void CompareInstances(const Instance& instanceA, const Instance& instanceB, bool shouldCompareLinkIds = true,
@@ -62,6 +64,8 @@ namespace UnitTest
//! Validates that all entities within a prefab instance are in 'Active' state.
void ValidateInstanceEntitiesActive(Instance& instance);
void AddRequiredEditorComponents(AZ::Entity* entity);
PrefabSystemComponent* m_prefabSystemComponent = nullptr;
PrefabLoaderInterface* m_prefabLoaderInterface = nullptr;
PrefabPublicInterface* m_prefabPublicInterface = nullptr;
@@ -128,7 +128,7 @@ namespace UnitTest
void ProcessDeferredUpdates()
{
// Force a prefab propagation for updates that are deferred to the next tick.
m_prefabSystemComponent->OnSystemTick();
PropagateAllTemplateChanges();
// Ensure the model process its entity update queue
m_model->ProcessEntityUpdates();
@@ -28,6 +28,9 @@ set(FILES
Entity/EditorEntitySearchComponentTests.cpp
Entity/EditorEntitySelectionTests.cpp
Entity/EntityUtilityComponentTests.cpp
Entity/ReadOnly/ReadOnlyEntityFixture.cpp
Entity/ReadOnly/ReadOnlyEntityFixture.h
Entity/ReadOnly/ReadOnlyEntityTests.cpp
EntityIdQLabelTests.cpp
EntityInspectorTests.cpp
EntityOwnershipService/EntityOwnershipServiceTestFixture.cpp
@@ -66,6 +69,7 @@ set(FILES
Prefab/PrefabFocus/PrefabFocusTests.cpp
Prefab/MockPrefabFileIOActionValidator.cpp
Prefab/MockPrefabFileIOActionValidator.h
Prefab/PrefabDeleteTests.cpp
Prefab/PrefabDuplicateTests.cpp
Prefab/PrefabEntityAliasTests.cpp
Prefab/PrefabInstanceToTemplatePropagatorTests.cpp