Merge branch 'development' into Prism/AddRepoDialog

monroegm-disable-blank-issue-2
nggieber 4 years ago
commit 4b73637ffd

@ -0,0 +1,7 @@
<svg width="24" height="33" viewBox="0 0 24 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" y="7" width="2" height="12" fill="#808080"/>
<rect x="5" y="19" width="2" height="14" fill="#808080"/>
<rect x="17" y="16" width="2" height="12" transform="rotate(90 17 16)" fill="#808080"/>
<circle cx="6" cy="6" r="2" fill="#808080"/>
<circle cx="18" cy="17" r="2" fill="#808080"/>
</svg>

After

Width:  |  Height:  |  Size: 398 B

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" width="2" height="12" fill="grey"/>
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="grey"/>
<circle cx="18" cy="13" r="2" fill="grey"/>
</svg>

After

Width:  |  Height:  |  Size: 280 B

@ -0,0 +1,6 @@
<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" width="2" height="12" fill="grey"/>
<rect x="5" y="14" width="2" height="12" fill="grey"/>
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="grey"/>
<circle cx="18" cy="13" r="2" fill="grey"/>
</svg>

After

Width:  |  Height:  |  Size: 335 B

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" y="7" width="2" height="7" fill="#808080"/>
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="#808080"/>
<circle cx="6" cy="6" r="2" fill="#808080"/>
<circle cx="18" cy="13" r="2" fill="#808080"/>
</svg>

After

Width:  |  Height:  |  Size: 339 B

@ -8098,7 +8098,7 @@
</message> </message>
<message id="COLOR_FROMVALUES_PARAM0_TOOLTIP"> <message id="COLOR_FROMVALUES_PARAM0_TOOLTIP">
<source>COLOR_FROMVALUES_PARAM0_TOOLTIP</source> <source>COLOR_FROMVALUES_PARAM0_TOOLTIP</source>
<translation type="unfinished">The Red value of hte Color [0, 255]</translation> <translation type="unfinished">The Red value of the Color [0.0-1.0]</translation>
</message> </message>
<message id="COLOR_FROMVALUES_PARAM1_NAME"> <message id="COLOR_FROMVALUES_PARAM1_NAME">
<source>COLOR_FROMVALUES_PARAM1_NAME</source> <source>COLOR_FROMVALUES_PARAM1_NAME</source>
@ -8107,7 +8107,7 @@
</message> </message>
<message id="COLOR_FROMVALUES_PARAM1_TOOLTIP"> <message id="COLOR_FROMVALUES_PARAM1_TOOLTIP">
<source>COLOR_FROMVALUES_PARAM1_TOOLTIP</source> <source>COLOR_FROMVALUES_PARAM1_TOOLTIP</source>
<translation type="unfinished">The Green value of the Color [0, 255]</translation> <translation type="unfinished">The Green value of the Color [0.0-1.0]</translation>
</message> </message>
<message id="COLOR_FROMVALUES_PARAM2_NAME"> <message id="COLOR_FROMVALUES_PARAM2_NAME">
<source>COLOR_FROMVALUES_PARAM2_NAME</source> <source>COLOR_FROMVALUES_PARAM2_NAME</source>
@ -8116,7 +8116,7 @@
</message> </message>
<message id="COLOR_FROMVALUES_PARAM2_TOOLTIP"> <message id="COLOR_FROMVALUES_PARAM2_TOOLTIP">
<source>COLOR_FROMVALUES_PARAM2_TOOLTIP</source> <source>COLOR_FROMVALUES_PARAM2_TOOLTIP</source>
<translation type="unfinished">The Blue value of the Color [0, 255]</translation> <translation type="unfinished">The Blue value of the Color [0.0-1.0]</translation>
</message> </message>
<message id="COLOR_FROMVALUES_PARAM3_NAME"> <message id="COLOR_FROMVALUES_PARAM3_NAME">
<source>COLOR_FROMVALUES_PARAM3_NAME</source> <source>COLOR_FROMVALUES_PARAM3_NAME</source>
@ -8125,7 +8125,7 @@
</message> </message>
<message id="COLOR_FROMVALUES_PARAM3_TOOLTIP"> <message id="COLOR_FROMVALUES_PARAM3_TOOLTIP">
<source>COLOR_FROMVALUES_PARAM3_TOOLTIP</source> <source>COLOR_FROMVALUES_PARAM3_TOOLTIP</source>
<translation type="unfinished">The Alpha value of the Color [0, 255]</translation> <translation type="unfinished">The Alpha value of the Color [0.0-1.0]</translation>
</message> </message>
</context> </context>
<context> <context>

@ -13,9 +13,9 @@
if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS) if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS)
ly_add_pytest( ly_add_pytest(
NAME AutomatedTesting::AtomRenderer_HydraTests_Main NAME AutomatedTesting::Atom_TestSuite_Main
TEST_SUITE main TEST_SUITE main
PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_MainSuite.py PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py
TEST_SERIAL TEST_SERIAL
TIMEOUT 600 TIMEOUT 600
RUNTIME_DEPENDENCIES RUNTIME_DEPENDENCIES
@ -26,9 +26,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
Atom Atom
) )
ly_add_pytest( ly_add_pytest(
NAME AutomatedTesting::AtomRenderer_HydraTests_MainOptimized NAME AutomatedTesting::Atom_TestSuite_Main_Optimized
TEST_SUITE main TEST_SUITE main
PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_MainSuite_Optimized.py PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
TEST_SERIAL TEST_SERIAL
TIMEOUT 600 TIMEOUT 600
RUNTIME_DEPENDENCIES RUNTIME_DEPENDENCIES
@ -39,9 +39,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
Atom Atom
) )
ly_add_pytest( ly_add_pytest(
NAME AutomatedTesting::AtomRenderer_HydraTests_Sandbox NAME AutomatedTesting::Atom_TestSuite_Sandbox
TEST_SUITE sandbox TEST_SUITE sandbox
PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_SandboxSuite.py PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Sandbox.py
TEST_SERIAL TEST_SERIAL
TIMEOUT 400 TIMEOUT 400
RUNTIME_DEPENDENCIES RUNTIME_DEPENDENCIES
@ -52,12 +52,12 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
Atom Atom
) )
ly_add_pytest( ly_add_pytest(
NAME AutomatedTesting::AtomRenderer_HydraTests_GPUTests NAME AutomatedTesting::Atom_TestSuite_Main_GPU
TEST_SUITE main TEST_SUITE main
TEST_REQUIRES gpu TEST_REQUIRES gpu
TEST_SERIAL TEST_SERIAL
TIMEOUT 1200 TIMEOUT 1200
PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_GPUTests.py PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_GPU.py
RUNTIME_DEPENDENCIES RUNTIME_DEPENDENCIES
AssetProcessor AssetProcessor
AutomatedTesting.Assets AutomatedTesting.Assets

@ -13,10 +13,10 @@ import pytest
import ly_test_tools.environment.file_system as file_system import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra import editor_python_test_tools.hydra_test_utils as hydra
from atom_renderer.atom_utils.atom_constants import LIGHT_TYPES from Atom.atom_utils.atom_constants import LIGHT_TYPES
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts") TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
@pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("project", ["AutomatedTesting"])
@ -38,24 +38,24 @@ class TestAtomEditorComponentsMain(object):
7. Exposure Control 7. Exposure Control
8. Directional Light 8. Directional Light
9. DepthOfField 9. DepthOfField
10. Decal (Atom) 10. Decal
""" """
cfg_args = [level] cfg_args = [level]
expected_lines = [ expected_lines = [
# Decal (Atom) Component # Decal Component
"Decal (Atom) Entity successfully created", "Decal Entity successfully created",
"Decal (Atom)_test: Component added to the entity: True", "Decal_test: Component added to the entity: True",
"Decal (Atom)_test: Component removed after UNDO: True", "Decal_test: Component removed after UNDO: True",
"Decal (Atom)_test: Component added after REDO: True", "Decal_test: Component added after REDO: True",
"Decal (Atom)_test: Entered game mode: True", "Decal_test: Entered game mode: True",
"Decal (Atom)_test: Exit game mode: True", "Decal_test: Exit game mode: True",
"Decal (Atom) Controller|Configuration|Material: SUCCESS", "Decal Controller|Configuration|Material: SUCCESS",
"Decal (Atom)_test: Entity is hidden: True", "Decal_test: Entity is hidden: True",
"Decal (Atom)_test: Entity is shown: True", "Decal_test: Entity is shown: True",
"Decal (Atom)_test: Entity deleted: True", "Decal_test: Entity deleted: True",
"Decal (Atom)_test: UNDO entity deletion works: True", "Decal_test: UNDO entity deletion works: True",
"Decal (Atom)_test: REDO entity deletion works: True", "Decal_test: REDO entity deletion works: True",
# DepthOfField Component # DepthOfField Component
"DepthOfField Entity successfully created", "DepthOfField Entity successfully created",
"DepthOfField_test: Component added to the entity: True", "DepthOfField_test: Component added to the entity: True",

@ -3,8 +3,6 @@ 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. For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT SPDX-License-Identifier: Apache-2.0 OR MIT
Tests that require a GPU in order to run.
""" """
import datetime import datetime
@ -22,7 +20,7 @@ import editor_python_test_tools.hydra_test_utils as hydra
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots' DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts") TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
def golden_images_directory(): def golden_images_directory():

@ -15,32 +15,32 @@ from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
class TestAutomation(EditorTestSuite): class TestAutomation(EditorTestSuite):
class AtomEditorComponents_DecalAdded(EditorSharedTest): class AtomEditorComponents_DecalAdded(EditorSharedTest):
from atom_renderer.atom_hydra_scripts import hydra_AtomEditorComponents_DecalAdded as test_module from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest): class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
from atom_renderer.atom_hydra_scripts import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest): class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
from atom_renderer.atom_hydra_scripts import hydra_AtomEditorComponents_DirectionalLightAdded as test_module from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
class AtomEditorComponents_ExposureControlAdded(EditorSharedTest): class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
from atom_renderer.atom_hydra_scripts import hydra_AtomEditorComponents_ExposureControlAdded as test_module from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest): class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
from atom_renderer.atom_hydra_scripts import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest): class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
from atom_renderer.atom_hydra_scripts import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest): class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
from atom_renderer.atom_hydra_scripts import ( from Atom.tests import (
hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module) hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
class AtomEditorComponents_LightAdded(EditorSharedTest): class AtomEditorComponents_LightAdded(EditorSharedTest):
from atom_renderer.atom_hydra_scripts import hydra_AtomEditorComponents_LightAdded as test_module from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest): class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
from atom_renderer.atom_hydra_scripts import hydra_AtomEditorComponents_DisplayMapperAdded as test_module from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
from .atom_hydra_scripts import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module

@ -2,7 +2,7 @@
{ {
"Source" : "DependencyValidation.azsl", "Source" : "DependencyValidation.azsl",
"DepthStencilState" : { "DepthStencilState" : {
"Depth" : { "Enable" : false, "CompareFunc" : "GreaterEqual" } "Depth" : { "Enable" : false, "CompareFunc" : "GreaterEqual" }
}, },
@ -22,5 +22,5 @@
} }
] ]
} }
} }

@ -184,7 +184,7 @@ def run():
material_asset = asset.AssetCatalogRequestBus( material_asset = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False) bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False)
ComponentTests( ComponentTests(
"Decal (Atom)", lambda entity_obj: verify_set_property( "Decal", lambda entity_obj: verify_set_property(
entity_obj, "Controller|Configuration|Material", material_asset)) entity_obj, "Controller|Configuration|Material", material_asset))
# Directional Light Component # Directional Light Component

@ -73,7 +73,7 @@ def AtomEditorComponents_Decal_AddedToEntity():
# Test steps begin. # Test steps begin.
# 1. Create a Decal entity with no components. # 1. Create a Decal entity with no components.
decal_name = "Decal (Atom)" decal_name = "Decal"
decal_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), decal_name) decal_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), decal_name)
Report.critical_result(Tests.decal_creation, decal_entity.exists()) Report.critical_result(Tests.decal_creation, decal_entity.exists())

@ -17,7 +17,7 @@ import azlmbr.legacy.general as general
sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests")) sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra import editor_python_test_tools.hydra_editor_utils as hydra
from atom_renderer.atom_utils.atom_constants import LIGHT_TYPES from Atom.atom_utils.atom_constants import LIGHT_TYPES
LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type' LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type'
SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES = [ SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES = [

@ -18,7 +18,7 @@ import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests")) sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
import atom_renderer.atom_utils.material_editor_utils as material_editor import Atom.atom_utils.material_editor_utils as material_editor
NEW_MATERIAL = "test_material.material" NEW_MATERIAL = "test_material.material"
NEW_MATERIAL_1 = "test_material_1.material" NEW_MATERIAL_1 = "test_material_1.material"

@ -14,7 +14,7 @@ sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "P
import editor_python_test_tools.hydra_editor_utils as hydra import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.editor_test_helper import EditorTestHelper from editor_python_test_tools.editor_test_helper import EditorTestHelper
from atom_renderer.atom_utils.benchmark_utils import BenchmarkHelper from Atom.atom_utils.benchmark_utils import BenchmarkHelper
SCREEN_WIDTH = 1280 SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720 SCREEN_HEIGHT = 720

@ -21,7 +21,7 @@ sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "P
import editor_python_test_tools.hydra_editor_utils as hydra import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.editor_test_helper import EditorTestHelper from editor_python_test_tools.editor_test_helper import EditorTestHelper
from atom_renderer.atom_utils.screenshot_utils import ScreenshotHelper from Atom.atom_utils.screenshot_utils import ScreenshotHelper
SCREEN_WIDTH = 1280 SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720 SCREEN_HEIGHT = 720

@ -17,7 +17,7 @@ import azlmbr.legacy.general as general
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra import editor_python_test_tools.hydra_editor_utils as hydra
from atom_renderer.atom_utils import atom_component_helper, atom_constants, screenshot_utils from Atom.atom_utils import atom_component_helper, atom_constants, screenshot_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper from editor_python_test_tools.editor_test_helper import EditorTestHelper
helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper") helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")

@ -18,7 +18,7 @@ include(${pal_dir}/PAL_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
add_subdirectory(assetpipeline) add_subdirectory(assetpipeline)
## Atom Renderer ## ## Atom Renderer ##
add_subdirectory(atom_renderer) add_subdirectory(Atom)
## Physics ## ## Physics ##
add_subdirectory(Physics) add_subdirectory(Physics)

@ -17,5 +17,14 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
AZ::AssetProcessorBatch AZ::AssetProcessorBatch
AZ::AssetProcessor AZ::AssetProcessor
) )
ly_add_pytest(
NAME AssetPipelineTests.Fbx_Tests
PATH ${CMAKE_CURRENT_LIST_DIR}/fbx_test/fbx_test.py
TEST_SUITE sandbox
RUNTIME_DEPENDENCIES
AZ::AssetProcessorBatch
AZ::AssetProcessor
)
endif() endif()

@ -34,11 +34,13 @@ logger = logging.getLogger(__name__)
targetProjects = ["AutomatedTesting"] targetProjects = ["AutomatedTesting"]
@pytest.fixture @pytest.fixture
@pytest.mark.SUITE_sandbox
def local_resources(request, workspace, ap_setup_fixture): def local_resources(request, workspace, ap_setup_fixture):
ap_setup_fixture["tests_dir"] = os.path.dirname(os.path.realpath(__file__)) ap_setup_fixture["tests_dir"] = os.path.dirname(os.path.realpath(__file__))
@dataclass @dataclass
@pytest.mark.SUITE_sandbox
class BlackboxAssetTest: class BlackboxAssetTest:
test_name: str test_name: str
asset_folder: str asset_folder: str
@ -338,9 +340,11 @@ blackbox_fbx_special_tests = [
@pytest.mark.usefixtures("local_resources") @pytest.mark.usefixtures("local_resources")
@pytest.mark.parametrize("project", targetProjects) @pytest.mark.parametrize("project", targetProjects)
@pytest.mark.assetpipeline @pytest.mark.assetpipeline
@pytest.mark.SUITE_sandbox
class TestsFBX_AllPlatforms(object): class TestsFBX_AllPlatforms(object):
@pytest.mark.BAT @pytest.mark.BAT
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize("blackbox_param", blackbox_fbx_tests) @pytest.mark.parametrize("blackbox_param", blackbox_fbx_tests)
def test_FBXBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace, def test_FBXBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace,
ap_setup_fixture, asset_processor, project, ap_setup_fixture, asset_processor, project,
@ -359,6 +363,7 @@ class TestsFBX_AllPlatforms(object):
asset_processor, project, blackbox_param) asset_processor, project, blackbox_param)
@pytest.mark.BAT @pytest.mark.BAT
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize("blackbox_param", blackbox_fbx_special_tests) @pytest.mark.parametrize("blackbox_param", blackbox_fbx_special_tests)
def test_FBXBlackboxTest_AssetInfoModified_AssetReprocessed_ResultInExpectedProducts(self, def test_FBXBlackboxTest_AssetInfoModified_AssetReprocessed_ResultInExpectedProducts(self,
workspace, ap_setup_fixture, workspace, ap_setup_fixture,

@ -254,4 +254,35 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_googletest( ly_add_googletest(
NAME Legacy::EditorLib.Tests NAME Legacy::EditorLib.Tests
) )
ly_add_target(
NAME EditorLib.Camera.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Legacy
FILES_CMAKE
Lib/Tests/Camera/editor_lib_camera_test_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
.
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
AZ::AzTest
AZ::AzToolsFramework
AZ::AzTestShared
Legacy::EditorLib
Gem::Camera.Editor
Gem::AtomToolsFramework.Static
RUNTIME_DEPENDENCIES
Legacy::EditorLib
)
ly_add_source_properties(
SOURCES Lib/Tests/Camera/test_EditorCamera.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES CAMERA_EDITOR_MODULE="$<TARGET_FILE_BASE_NAME:Camera.Editor>"
)
ly_add_googletest(
NAME Legacy::EditorLib.Camera.Tests
)
endif() endif()

@ -9,6 +9,7 @@
#include <EditorModularViewportCameraComposer.h> #include <EditorModularViewportCameraComposer.h>
#include <AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h> #include <AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/std/smart_ptr/make_shared.h> #include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/Render/IntersectorInterface.h> #include <AzFramework/Render/IntersectorInterface.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h> #include <AzToolsFramework/Viewport/ViewportMessages.h>
@ -34,10 +35,12 @@ namespace SandboxEditor
: m_viewportId(viewportId) : m_viewportId(viewportId)
{ {
EditorModularViewportCameraComposerNotificationBus::Handler::BusConnect(viewportId); EditorModularViewportCameraComposerNotificationBus::Handler::BusConnect(viewportId);
Camera::EditorCameraNotificationBus::Handler::BusConnect();
} }
EditorModularViewportCameraComposer::~EditorModularViewportCameraComposer() EditorModularViewportCameraComposer::~EditorModularViewportCameraComposer()
{ {
Camera::EditorCameraNotificationBus::Handler::BusDisconnect();
EditorModularViewportCameraComposerNotificationBus::Handler::BusDisconnect(); EditorModularViewportCameraComposerNotificationBus::Handler::BusDisconnect();
} }
@ -283,4 +286,22 @@ namespace SandboxEditor
m_orbitCamera->SetOrbitInputChannelId(SandboxEditor::CameraOrbitChannelId()); m_orbitCamera->SetOrbitInputChannelId(SandboxEditor::CameraOrbitChannelId());
m_orbitDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraOrbitDollyChannelId()); m_orbitDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraOrbitDollyChannelId());
} }
void EditorModularViewportCameraComposer::OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId)
{
if (viewEntityId.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, viewEntityId, &AZ::TransformBus::Events::GetWorldTM);
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame,
worldFromLocal);
}
else
{
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::ClearReferenceFrame);
}
}
} // namespace SandboxEditor } // namespace SandboxEditor

@ -10,13 +10,16 @@
#include <AtomToolsFramework/Viewport/ModularViewportCameraController.h> #include <AtomToolsFramework/Viewport/ModularViewportCameraController.h>
#include <AzFramework/Viewport/CameraInput.h> #include <AzFramework/Viewport/CameraInput.h>
#include <AzToolsFramework/API/EditorCameraBus.h>
#include <EditorModularViewportCameraComposerBus.h> #include <EditorModularViewportCameraComposerBus.h>
#include <SandboxAPI.h> #include <SandboxAPI.h>
namespace SandboxEditor namespace SandboxEditor
{ {
//! Type responsible for building the editor's modular viewport camera controller. //! Type responsible for building the editor's modular viewport camera controller.
class EditorModularViewportCameraComposer : private EditorModularViewportCameraComposerNotificationBus::Handler class EditorModularViewportCameraComposer
: private EditorModularViewportCameraComposerNotificationBus::Handler
, private Camera::EditorCameraNotificationBus::Handler
{ {
public: public:
SANDBOX_API explicit EditorModularViewportCameraComposer(AzFramework::ViewportId viewportId); SANDBOX_API explicit EditorModularViewportCameraComposer(AzFramework::ViewportId viewportId);
@ -32,6 +35,9 @@ namespace SandboxEditor
// EditorModularViewportCameraComposerNotificationBus overrides ... // EditorModularViewportCameraComposerNotificationBus overrides ...
void OnEditorModularViewportCameraComposerSettingsChanged() override; void OnEditorModularViewportCameraComposerSettingsChanged() override;
// EditorCameraNotificationBus overrides ...
void OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId) override;
AZStd::shared_ptr<AzFramework::RotateCameraInput> m_firstPersonRotateCamera; AZStd::shared_ptr<AzFramework::RotateCameraInput> m_firstPersonRotateCamera;
AZStd::shared_ptr<AzFramework::PanCameraInput> m_firstPersonPanCamera; AZStd::shared_ptr<AzFramework::PanCameraInput> m_firstPersonPanCamera;
AZStd::shared_ptr<AzFramework::TranslateCameraInput> m_firstPersonTranslateCamera; AZStd::shared_ptr<AzFramework::TranslateCameraInput> m_firstPersonTranslateCamera;

@ -0,0 +1,225 @@
/*
* 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 <AZTestShared/Math/MathTestHelpers.h>
#include <AtomToolsFramework/Viewport/ModularViewportCameraController.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/Viewport/ViewportControllerList.h>
#include <AzTest/GemTestEnvironment.h>
#include <AzToolsFramework/API/EditorCameraBus.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <EditorModularViewportCameraComposer.h>
namespace UnitTest
{
class EditorCameraTestEnvironment : public AZ::Test::GemTestEnvironment
{
// AZ::Test::GemTestEnvironment overrides ...
void AddGemsAndComponents() override;
};
void EditorCameraTestEnvironment::AddGemsAndComponents()
{
AddDynamicModulePaths({ CAMERA_EDITOR_MODULE });
AddComponentDescriptors({ AzToolsFramework::Components::TransformComponent::CreateDescriptor() });
}
class EditorCameraFixture : public ::testing::Test
{
public:
AtomToolsFramework::ModularCameraViewportContext* m_cameraViewportContextView = nullptr;
AZStd::unique_ptr<SandboxEditor::EditorModularViewportCameraComposer> m_editorModularViewportCameraComposer;
AZStd::unique_ptr<AZ::DynamicModuleHandle> m_editorLibHandle;
AzFramework::ViewportControllerListPtr m_controllerList;
AZStd::unique_ptr<AZ::Entity> m_entity;
static const AzFramework::ViewportId TestViewportId;
void SetUp() override
{
m_editorLibHandle = AZ::DynamicModuleHandle::Create("EditorLib");
[[maybe_unused]] const bool loaded = m_editorLibHandle->Load(true);
AZ_Assert(loaded, "EditorLib could not be loaded");
m_controllerList = AZStd::make_shared<AzFramework::ViewportControllerList>();
m_controllerList->RegisterViewportContext(TestViewportId);
m_entity = AZStd::make_unique<AZ::Entity>();
m_entity->Init();
m_entity->CreateComponent<AzToolsFramework::Components::TransformComponent>();
m_entity->Activate();
m_editorModularViewportCameraComposer = AZStd::make_unique<SandboxEditor::EditorModularViewportCameraComposer>(TestViewportId);
auto controller = m_editorModularViewportCameraComposer->CreateModularViewportCameraController();
// set some overrides for the test
controller->SetCameraViewportContextBuilderCallback(
[this](AZStd::unique_ptr<AtomToolsFramework::ModularCameraViewportContext>& cameraViewportContext) mutable
{
cameraViewportContext = AZStd::make_unique<AtomToolsFramework::PlaceholderModularCameraViewportContextImpl>();
m_cameraViewportContextView = cameraViewportContext.get();
});
m_controllerList->Add(controller);
}
void TearDown() override
{
m_editorModularViewportCameraComposer.reset();
m_cameraViewportContextView = nullptr;
m_entity.reset();
m_editorLibHandle = {};
}
};
const AzFramework::ViewportId EditorCameraFixture::TestViewportId = AzFramework::ViewportId(1337);
TEST_F(EditorCameraFixture, ModularViewportCameraControllerReferenceFrameUpdatedWhenViewportEntityisChanged)
{
// Given
const auto entityTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(10.0f, 5.0f, -2.0f));
AZ::TransformBus::Event(m_entity->GetId(), &AZ::TransformBus::Events::SetWorldTM, entityTransform);
// When
// imitate viewport entity changing
Camera::EditorCameraNotificationBus::Broadcast(
&Camera::EditorCameraNotificationBus::Events::OnViewportViewEntityChanged, m_entity->GetId());
// ensure the viewport updates after the viewport view entity change
const float deltaTime = 1.0f / 60.0f;
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() });
// retrieve updated camera transform
const AZ::Transform cameraTransform = m_cameraViewportContextView->GetCameraTransform();
// Then
// camera transform matches that of the entity
EXPECT_THAT(cameraTransform, IsClose(entityTransform));
}
TEST_F(EditorCameraFixture, ReferenceFrameRemainsIdentityAfterExternalCameraTransformChangeWhenNotSet)
{
// Given
m_cameraViewportContextView->SetCameraTransform(AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 20.0f, 30.0f)));
// When
AZ::Transform referenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
referenceFrame, TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
// Then
// reference frame is still the identity
EXPECT_THAT(referenceFrame, IsClose(AZ::Transform::CreateIdentity()));
}
TEST_F(EditorCameraFixture, ExternalCameraTransformChangeWhenReferenceFrameIsSetUpdatesReferenceFrame)
{
// Given
const AZ::Transform referenceFrame = AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(1.0f, 2.0f, 3.0f));
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, referenceFrame);
const AZ::Transform nextTransform = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 20.0f, 30.0f));
m_cameraViewportContextView->SetCameraTransform(nextTransform);
// When
AZ::Transform currentReferenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
currentReferenceFrame, TestViewportId,
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
// Then
EXPECT_THAT(currentReferenceFrame, IsClose(nextTransform));
}
TEST_F(EditorCameraFixture, ReferenceFrameReturnedToIdentityAfterClear)
{
// Given
const AZ::Transform referenceFrame = AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(1.0f, 2.0f, 3.0f));
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, referenceFrame);
// When
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::ClearReferenceFrame);
AZ::Transform currentReferenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
currentReferenceFrame, TestViewportId,
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
// Then
EXPECT_THAT(currentReferenceFrame, IsClose(AZ::Transform::CreateIdentity()));
}
TEST_F(EditorCameraFixture, InterpolateToTransform)
{
// When
AZ::Transform transformToInterpolateTo = AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(20.0f, 40.0f, 60.0f));
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform,
transformToInterpolateTo, 0.0f);
// simulate interpolation
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
const auto finalTransform = m_cameraViewportContextView->GetCameraTransform();
// Then
EXPECT_THAT(finalTransform, IsClose(transformToInterpolateTo));
}
TEST_F(EditorCameraFixture, InterpolateToTransformWithReferenceSpaceSet)
{
// Given
const AZ::Transform referenceFrame = AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(1.0f, 2.0f, 3.0f));
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, referenceFrame);
AZ::Transform transformToInterpolateTo = AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(20.0f, 40.0f, 60.0f));
// When
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform,
transformToInterpolateTo, 0.0f);
// simulate interpolation
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
AZ::Transform currentReferenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
currentReferenceFrame, TestViewportId,
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
const auto finalTransform = m_cameraViewportContextView->GetCameraTransform();
// Then
EXPECT_THAT(finalTransform, IsClose(transformToInterpolateTo));
EXPECT_THAT(currentReferenceFrame, IsClose(AZ::Transform::CreateIdentity()));
}
} // namespace UnitTest
// required to support running integration tests with the Camera Gem
AZTEST_EXPORT int AZ_UNIT_TEST_HOOK_NAME(int argc, char** argv)
{
::testing::InitGoogleMock(&argc, argv);
AZ::Test::printUnusedParametersWarning(argc, argv);
AZ::Test::addTestEnvironments({ new UnitTest::EditorCameraTestEnvironment() });
int result = RUN_ALL_TESTS();
return result;
}
IMPLEMENT_TEST_EXECUTABLE_MAIN();

@ -58,28 +58,6 @@ namespace UnitTest
return true; return true;
} }
class TestModularCameraViewportContextImpl : public AtomToolsFramework::ModularCameraViewportContext
{
public:
AZ::Transform GetCameraTransform() const override
{
return m_cameraTransform;
}
void SetCameraTransform(const AZ::Transform& transform) override
{
m_cameraTransform = transform;
}
void ConnectViewMatrixChangedHandler(AZ::RPI::ViewportContext::MatrixChangedEvent::Handler&) override
{
// noop
}
private:
AZ::Transform m_cameraTransform = AZ::Transform::CreateIdentity();
};
class ModularViewportCameraControllerFixture : public AllocatorsTestFixture class ModularViewportCameraControllerFixture : public AllocatorsTestFixture
{ {
public: public:
@ -146,7 +124,7 @@ namespace UnitTest
controller->SetCameraViewportContextBuilderCallback( controller->SetCameraViewportContextBuilderCallback(
[this](AZStd::unique_ptr<AtomToolsFramework::ModularCameraViewportContext>& cameraViewportContext) [this](AZStd::unique_ptr<AtomToolsFramework::ModularCameraViewportContext>& cameraViewportContext)
{ {
cameraViewportContext = AZStd::make_unique<TestModularCameraViewportContextImpl>(); cameraViewportContext = AZStd::make_unique<AtomToolsFramework::PlaceholderModularCameraViewportContextImpl>();
m_cameraViewportContextView = cameraViewportContext.get(); m_cameraViewportContextView = cameraViewportContext.get();
}); });

@ -207,12 +207,6 @@ namespace AZ
ActivateComponent(**it); ActivateComponent(**it);
} }
// Cache the transform interface to the transform interface
// Generally this pattern is not recommended unless for component event buses
// As we have a guarantee (by design) that components can't change during active state)
// Even though technically they can connect disconnect from the bus.
m_transform = TransformBus::FindFirstHandler(m_id);
SetState(State::Active); SetState(State::Active);
EBUS_EVENT_ID(m_id, EntityBus, OnEntityActivated, m_id); EBUS_EVENT_ID(m_id, EntityBus, OnEntityActivated, m_id);
@ -1320,6 +1314,19 @@ namespace AZ
return *processSignature; return *processSignature;
} }
AZ::TransformInterface* Entity::GetTransform() const
{
// Lazy evaluation of the cached entity transform.
if(!m_transform)
{
// Generally this pattern is not recommended unless for component event buses
// As we have a guarantee (by design) that components can't change during active state)
// Even though technically they can connect disconnect from the bus.
m_transform = TransformBus::FindFirstHandler(m_id);
}
return m_transform;
}
//========================================================================= //=========================================================================
// MakeId // MakeId
// Ids must be unique across a project at authoring time. Runtime doesn't matter // Ids must be unique across a project at authoring time. Runtime doesn't matter

@ -354,10 +354,9 @@ namespace AZ
//! @return The Process Signature of the local machine. //! @return The Process Signature of the local machine.
static AZ::u32 GetProcessSignature(); static AZ::u32 GetProcessSignature();
/// @cond EXCLUDE_DOCS //! Gets the TransformInterface for the entity.
//! @deprecated Use the TransformBus to communicate with the TransformInterface. //! @return The TransformInterface for the entity.
inline TransformInterface* GetTransform() const { return m_transform; } TransformInterface* GetTransform() const;
/// @endcond
//! Sorts an entity's components based on the dependencies between components. //! Sorts an entity's components based on the dependencies between components.
//! If all dependencies are met, the required services can be activated //! If all dependencies are met, the required services can be activated
@ -406,7 +405,7 @@ namespace AZ
//! A cached pointer to the transform interface. //! A cached pointer to the transform interface.
//! We recommend using AZ::TransformBus and caching locally instead of accessing //! We recommend using AZ::TransformBus and caching locally instead of accessing
//! the transform interface directly through this pointer. //! the transform interface directly through this pointer.
TransformInterface* m_transform; mutable TransformInterface* m_transform;
//! A user-friendly name for the entity. This makes error messages easier to read. //! A user-friendly name for the entity. This makes error messages easier to read.
AZStd::string m_name; AZStd::string m_name;

@ -0,0 +1,200 @@
/*
* 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/IO/FileReader.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/Path/Path.h>
namespace AZ::IO
{
FileReader::FileReader() = default;
FileReader::FileReader(AZ::IO::FileIOBase* fileIoBase, const char* filePath)
{
Open(fileIoBase, filePath);
}
FileReader::~FileReader()
{
Close();
}
FileReader::FileReader(FileReader&& other)
{
AZStd::swap(m_file, other.m_file);
AZStd::swap(m_fileIoBase, other.m_fileIoBase);
}
FileReader& FileReader::operator=(FileReader&& other)
{
// Close the current file and take over other file
Close();
m_file = AZStd::move(other.m_file);
m_fileIoBase = AZStd::move(other.m_fileIoBase);
other.m_file = AZStd::monostate{};
other.m_fileIoBase = {};
return *this;
}
bool FileReader::Open(AZ::IO::FileIOBase* fileIoBase, const char* filePath)
{
// Close file if the FileReader has an instance open
Close();
if (fileIoBase != nullptr)
{
AZ::IO::HandleType fileHandle;
if (fileIoBase->Open(filePath, IO::OpenMode::ModeRead, fileHandle))
{
m_file = fileHandle;
m_fileIoBase = fileIoBase;
return true;
}
}
else
{
AZ::IO::SystemFile file;
if (file.Open(filePath, IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY))
{
m_file = AZStd::move(file);
return true;
}
}
return false;
}
bool FileReader::IsOpen() const
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
return *fileHandle != AZ::IO::InvalidHandle;
}
else if (auto systemFile = AZStd::get_if<AZ::IO::SystemFile>(&m_file); systemFile != nullptr)
{
return systemFile->IsOpen();
}
return false;
}
void FileReader::Close()
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
if (AZ::IO::FileIOBase* fileIo = m_fileIoBase; fileIo != nullptr)
{
fileIo->Close(*fileHandle);
}
}
m_file = AZStd::monostate{};
m_fileIoBase = {};
}
auto FileReader::Length() const -> SizeType
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
if (SizeType fileSize{}; m_fileIoBase->Size(*fileHandle, fileSize))
{
return fileSize;
}
}
else if (auto systemFile = AZStd::get_if<AZ::IO::SystemFile>(&m_file); systemFile != nullptr)
{
return systemFile->Length();
}
return 0;
}
auto FileReader::Read(SizeType byteSize, void* buffer) -> SizeType
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
if (SizeType bytesRead{}; m_fileIoBase->Read(*fileHandle, buffer, byteSize, false, &bytesRead))
{
return bytesRead;
}
}
else if (auto systemFile = AZStd::get_if<AZ::IO::SystemFile>(&m_file); systemFile != nullptr)
{
return systemFile->Read(byteSize, buffer);
}
return 0;
}
auto FileReader::Tell() const -> SizeType
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
if (SizeType fileOffset{}; m_fileIoBase->Tell(*fileHandle, fileOffset))
{
return fileOffset;
}
}
else if (auto systemFile = AZStd::get_if<AZ::IO::SystemFile>(&m_file); systemFile != nullptr)
{
return systemFile->Tell();
}
return 0;
}
bool FileReader::Seek(AZ::s64 offset, SeekType type)
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
return m_fileIoBase->Seek(*fileHandle, offset, type);
}
else if (auto systemFile = AZStd::get_if<AZ::IO::SystemFile>(&m_file); systemFile != nullptr)
{
systemFile->Seek(offset, static_cast<AZ::IO::SystemFile::SeekMode>(type));
return true;
}
return false;
}
bool FileReader::Eof() const
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
return m_fileIoBase->Eof(*fileHandle);
}
else if (auto systemFile = AZStd::get_if<AZ::IO::SystemFile>(&m_file); systemFile != nullptr)
{
return systemFile->Eof();
}
return false;
}
bool FileReader::GetFilePath(AZ::IO::FixedMaxPath& filePath) const
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
AZ::IO::FixedMaxPathString& pathStringRef = filePath.Native();
if (m_fileIoBase->GetFilename(*fileHandle, pathStringRef.data(), pathStringRef.capacity()))
{
pathStringRef.resize_no_construct(AZStd::char_traits<char>::length(pathStringRef.data()));
return true;
}
}
else if (auto systemFile = AZStd::get_if<AZ::IO::SystemFile>(&m_file); systemFile != nullptr)
{
filePath = systemFile->Name();
return true;
}
return false;
}
}

@ -0,0 +1,92 @@
/*
* 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/IO/Path/Path_fwd.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/std/containers/variant.h>
namespace AZ::IO
{
class FileIOBase;
enum class SeekType : AZ::u32;
//! Structure which encapsulates delegates File Read operations
//! to either the FileIOBase or SystemFile classes based if a FileIOBase* instance has been supplied
//! to the FileSystemReader class
//! the SettingsRegistry option to use FileIO
class FileReader
{
using HandleType = AZ::u32;
using FileHandleType = AZStd::variant<AZStd::monostate, AZ::IO::SystemFile, HandleType>;
public:
using SizeType = AZ::u64;
//! Creates FileReader instance in the default state with no file opend
FileReader();
~FileReader();
//! Creates a new FileReader instance and attempts to open the file at the supplied path
//! Uses the FileIOBase instance if supplied
//! @param fileIOBase pointer to fileIOBase instance
//! @param null-terminated filePath to open
FileReader(AZ::IO::FileIOBase* fileIoBase, const char* filePath);
//! Takes ownership of the supplied FileReader handle
FileReader(FileReader&& other);
//! Moves ownership of FileReader handle to this instance
FileReader& operator=(FileReader&& other);
//! Opens a File using the FileIOBase instance if non-nullptr
//! Otherwise fall back to use SystemFile
//! @param fileIOBase pointer to fileIOBase instance
//! @param null-terminated filePath to open
//! @return true if the File is opened successfully
bool Open(AZ::IO::FileIOBase* fileIoBase, const char* filePath);
//! Returns true if a file is currently open
//! @return true if the file is open
bool IsOpen() const;
//! Closes the File
void Close();
//! Retrieve the length of the OpenFile
SizeType Length() const;
//! Attempts to read up to byte size bytes into the supplied buffer
//! @param byteSize - Maximum number of bytes to read
//! @param buffer - Buffer to read bytes into
//! @returns the number of bytes read if the file is open, otherwise 0
SizeType Read(SizeType byteSize, void* buffer);
//! Returns the current file offset
//! @returns file offset if the file is open, otherwise 0
SizeType Tell() const;
//! Seeks within the open file to the offset supplied
//! @param offset File offset to seek to
//! @param type parameter to indicate the reference point to start the seek from
//! @returns true if the file is open and the seek succeeded
bool Seek(AZ::s64 offset, SeekType type);
//! Returns true if the file is open and in the EOF state
bool Eof() const;
//! Store the file path of the open file into the output file path parameter
//! The filePath reference is left unmodified, if the path was not stored
//! @return true if the filePath was stored
bool GetFilePath(AZ::IO::FixedMaxPath& filePath) const;
private:
FileHandleType m_file;
AZ::IO::FileIOBase* m_fileIoBase{};
};
}

@ -160,12 +160,12 @@ void SystemFile::Seek(SeekSizeType offset, SeekMode mode)
Platform::Seek(m_handle, this, offset, mode); Platform::Seek(m_handle, this, offset, mode);
} }
SystemFile::SizeType SystemFile::Tell() SystemFile::SizeType SystemFile::Tell() const
{ {
return Platform::Tell(m_handle, this); return Platform::Tell(m_handle, this);
} }
bool SystemFile::Eof() bool SystemFile::Eof() const
{ {
return Platform::Eof(m_handle, this); return Platform::Eof(m_handle, this);
} }

@ -72,9 +72,9 @@ namespace AZ
/// Seek in current file. /// Seek in current file.
void Seek(SeekSizeType offset, SeekMode mode); void Seek(SeekSizeType offset, SeekMode mode);
/// Get the cursor position in the current file. /// Get the cursor position in the current file.
SizeType Tell(); SizeType Tell() const;
/// Is the cursor at the end of the file? /// Is the cursor at the end of the file?
bool Eof(); bool Eof() const;
/// Get the time the file was last modified. /// Get the time the file was last modified.
AZ::u64 ModificationTime(); AZ::u64 ModificationTime();
/// Read data from a file synchronous. Return number of bytes actually read in the buffer. /// Read data from a file synchronous. Return number of bytes actually read in the buffer.

@ -353,6 +353,7 @@ namespace AZ
Method("CreateFromMatrix3x3AndTranslation", &Transform::CreateFromMatrix3x3AndTranslation)-> Method("CreateFromMatrix3x3AndTranslation", &Transform::CreateFromMatrix3x3AndTranslation)->
Method("CreateUniformScale", &Transform::CreateUniformScale)-> Method("CreateUniformScale", &Transform::CreateUniformScale)->
Method("CreateTranslation", &Transform::CreateTranslation)-> Method("CreateTranslation", &Transform::CreateTranslation)->
Method("CreateLookAt", &Transform::CreateLookAt)->
Method("ConstructFromValuesNumeric", &Internal::ConstructTransformFromValues); Method("ConstructFromValuesNumeric", &Internal::ConstructTransformFromValues);
} }
} }

@ -10,6 +10,7 @@
#include <cerrno> #include <cerrno>
#include <AzCore/Casting/numeric_cast.h> #include <AzCore/Casting/numeric_cast.h>
#include <AzCore/IO/FileIO.h> #include <AzCore/IO/FileIO.h>
#include <AzCore/IO/FileReader.h>
#include <AzCore/IO/Path/Path.h> #include <AzCore/IO/Path/Path.h>
#include <AzCore/JSON/error/en.h> #include <AzCore/JSON/error/en.h>
#include <AzCore/NativeUI//NativeUIRequests.h> #include <AzCore/NativeUI//NativeUIRequests.h>
@ -1116,118 +1117,6 @@ namespace AZ
} }
} }
//! Structure which encapsulates Commands to either the FileIOBase or SystemFile classes based on
//! the SettingsRegistry option to use FileIO
struct SettingsRegistryFileReader
{
using FileHandleType = AZStd::variant<AZStd::monostate, AZ::IO::SystemFile, AZ::IO::HandleType>;
SettingsRegistryFileReader() = default;
SettingsRegistryFileReader(bool useFileIo, const char* filePath)
{
Open(useFileIo, filePath);
}
~SettingsRegistryFileReader()
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
if (AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance(); fileIo != nullptr)
{
fileIo->Close(*fileHandle);
}
}
}
bool Open(bool useFileIo, const char* filePath)
{
Close();
if (AZ::IO::FileIOBase* fileIo = useFileIo ? AZ::IO::FileIOBase::GetInstance() : nullptr; fileIo != nullptr)
{
AZ::IO::HandleType fileHandle;
if (fileIo->Open(filePath, IO::OpenMode::ModeRead, fileHandle))
{
m_file = fileHandle;
return true;
}
}
else
{
AZ::IO::SystemFile file;
if (file.Open(filePath, IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY))
{
m_file = AZStd::move(file);
return true;
}
}
return false;
}
bool IsOpen() const
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
return *fileHandle != AZ::IO::InvalidHandle;
}
else if (auto systemFile = AZStd::get_if<AZ::IO::SystemFile>(&m_file); systemFile != nullptr)
{
return systemFile->IsOpen();
}
return false;
}
void Close()
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
if (AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance(); fileIo != nullptr)
{
fileIo->Close(*fileHandle);
}
}
m_file = AZStd::monostate{};
}
u64 Length() const
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
if (u64 fileSize{}; AZ::IO::FileIOBase::GetInstance()->Size(*fileHandle, fileSize))
{
return fileSize;
}
}
else if (auto systemFile = AZStd::get_if<AZ::IO::SystemFile>(&m_file); systemFile != nullptr)
{
return systemFile->Length();
}
return 0;
}
AZ::IO::SizeType Read(AZ::IO::SizeType byteSize, void* buffer)
{
if (auto fileHandle = AZStd::get_if<AZ::IO::HandleType>(&m_file); fileHandle != nullptr)
{
if (AZ::u64 bytesRead{}; AZ::IO::FileIOBase::GetInstance()->Read(*fileHandle, buffer, byteSize, false, &bytesRead))
{
return bytesRead;
}
}
else if (auto systemFile = AZStd::get_if<AZ::IO::SystemFile>(&m_file); systemFile != nullptr)
{
return systemFile->Read(byteSize, buffer);
}
return 0;
}
FileHandleType m_file;
};
bool SettingsRegistryImpl::MergeSettingsFileInternal(const char* path, Format format, AZStd::string_view rootKey, bool SettingsRegistryImpl::MergeSettingsFileInternal(const char* path, Format format, AZStd::string_view rootKey,
AZStd::vector<char>& scratchBuffer) AZStd::vector<char>& scratchBuffer)
{ {
@ -1236,7 +1125,7 @@ namespace AZ
Pointer pointer(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/-"); Pointer pointer(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/-");
SettingsRegistryFileReader fileReader(m_useFileIo, path); FileReader fileReader(m_useFileIo ? AZ::IO::FileIOBase::GetInstance(): nullptr, path);
if (!fileReader.IsOpen()) if (!fileReader.IsOpen())
{ {
AZ_Error("Settings Registry", false, R"(Unable to open registry file "%s".)", path); AZ_Error("Settings Registry", false, R"(Unable to open registry file "%s".)", path);

@ -6,6 +6,8 @@
* *
*/ */
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/FileReader.h>
#include <AzCore/IO/GenericStreams.h> #include <AzCore/IO/GenericStreams.h>
#include <AzCore/IO/Path/Path.h> #include <AzCore/IO/Path/Path.h>
#include <AzCore/IO/TextStreamWriters.h> #include <AzCore/IO/TextStreamWriters.h>
@ -388,8 +390,36 @@ namespace AZ::SettingsRegistryMergeUtils
const ConfigParserSettings& configParserSettings) const ConfigParserSettings& configParserSettings)
{ {
auto configPath = FindEngineRoot(registry) / filePath; auto configPath = FindEngineRoot(registry) / filePath;
IO::SystemFile configFile; IO::FileReader configFile;
if (!configFile.Open(configPath.c_str(), IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY)) bool configFileOpened{};
switch (configParserSettings.m_fileReaderClass)
{
case ConfigParserSettings::FileReaderClass::UseFileIOIfAvailableFallbackToSystemFile:
{
auto fileIo = AZ::IO::FileIOBase::GetInstance();
configFileOpened = configFile.Open(fileIo, configPath.c_str());
break;
}
case ConfigParserSettings::FileReaderClass::UseSystemFileOnly:
{
configFileOpened = configFile.Open(nullptr, configPath.c_str());
break;
}
case ConfigParserSettings::FileReaderClass::UseFileIOOnly:
{
auto fileIo = AZ::IO::FileIOBase::GetInstance();
if (fileIo == nullptr)
{
return false;
}
configFileOpened = configFile.Open(fileIo, configPath.c_str());
break;
}
default:
AZ_Error("SettingsRegistryMergeUtils", false, "An Invalid FileReaderClass enum value has been supplied");
return false;
}
if (!configFileOpened)
{ {
AZ_Warning("SettingsRegistryMergeUtils", false, R"(Unable to open file "%s")", configPath.c_str()); AZ_Warning("SettingsRegistryMergeUtils", false, R"(Unable to open file "%s")", configPath.c_str());
return false; return false;
@ -480,7 +510,7 @@ namespace AZ::SettingsRegistryMergeUtils
AZ_Error("SettingsRegistryMergeUtils", false, AZ_Error("SettingsRegistryMergeUtils", false,
R"(The config file "%s" contains a line which is longer than the max line length of %zu.)" "\n" R"(The config file "%s" contains a line which is longer than the max line length of %zu.)" "\n"
R"(Parsing will halt. The line content so far is:)" "\n" R"(Parsing will halt. The line content so far is:)" "\n"
R"("%.*s")" "\n", configFile.Name(), configBuffer.max_size(), R"("%.*s")" "\n", configPath.c_str(), configBuffer.max_size(),
aznumeric_cast<int>(configBuffer.size()), configBuffer.data()); aznumeric_cast<int>(configBuffer.size()), configBuffer.data());
configFileParsed = false; configFileParsed = false;
break; break;

@ -155,6 +155,15 @@ namespace AZ::SettingsRegistryMergeUtils
//! structure which is forwarded to the SettingsRegistryInterface MergeCommandLineArgument function //! structure which is forwarded to the SettingsRegistryInterface MergeCommandLineArgument function
//! The structure contains a functor which returns true if a character is a valid delimiter //! The structure contains a functor which returns true if a character is a valid delimiter
SettingsRegistryInterface::CommandLineArgumentSettings m_commandLineSettings; SettingsRegistryInterface::CommandLineArgumentSettings m_commandLineSettings;
//! enumeration to indicate if AZ::IO::FileIOBase should be used to open the config file over AZ::IO::SystemFile
enum class FileReaderClass
{
UseFileIOIfAvailableFallbackToSystemFile,
UseSystemFileOnly,
UseFileIOOnly
};
FileReaderClass m_fileReaderClass = FileReaderClass::UseFileIOIfAvailableFallbackToSystemFile;
}; };
//! Loads basic configuration files which have structures similar to Windows INI files //! Loads basic configuration files which have structures similar to Windows INI files
//! It is inspired by the Python configparser module: https://docs.python.org/3.10/library/configparser.html //! It is inspired by the Python configparser module: https://docs.python.org/3.10/library/configparser.html

@ -166,6 +166,8 @@ set(FILES
IO/FileIO.cpp IO/FileIO.cpp
IO/FileIO.h IO/FileIO.h
IO/FileIOEventBus.h IO/FileIOEventBus.h
IO/FileReader.cpp
IO/FileReader.h
IO/IOUtils.h IO/IOUtils.h
IO/IOUtils.cpp IO/IOUtils.cpp
IO/IStreamer.h IO/IStreamer.h

@ -0,0 +1,72 @@
/*
* 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/IO/FileReader.h>
#include <FileIOBaseTestTypes.h>
#include <AzCore/UnitTest/TestTypes.h>
namespace UnitTest
{
template <typename FileIOType>
class FileReaderTestFixture
: public ScopedAllocatorSetupFixture
{
public:
void SetUp() override
{
if constexpr (AZStd::is_same_v<FileIOType, TestFileIOBase>)
{
m_fileIo = AZStd::make_unique<TestFileIOBase>();
}
}
void TearDown() override
{
m_fileIo.reset();
}
protected:
AZStd::unique_ptr<AZ::IO::FileIOBase> m_fileIo{};
};
using FileIOTypes = ::testing::Types<void, TestFileIOBase>;
TYPED_TEST_CASE(FileReaderTestFixture, FileIOTypes);
TYPED_TEST(FileReaderTestFixture, ConstructorWithFilePath_OpensFileSuccessfully)
{
AZ::IO::FileReader fileReader(this->m_fileIo.get(), AZ::IO::SystemFile::GetNullFilename());
EXPECT_TRUE(fileReader.IsOpen());
}
TYPED_TEST(FileReaderTestFixture, Open_OpensFileSucessfully)
{
AZ::IO::FileReader fileReader;
fileReader.Open(this->m_fileIo.get(), AZ::IO::SystemFile::GetNullFilename());
EXPECT_TRUE(fileReader.IsOpen());
}
TYPED_TEST(FileReaderTestFixture, Eof_OnNULDeviceFile_Succeeds)
{
AZ::IO::FileReader fileReader(this->m_fileIo.get(), AZ::IO::SystemFile::GetNullFilename());
EXPECT_TRUE(fileReader.Eof());
}
TYPED_TEST(FileReaderTestFixture, GetFilePath_ReturnsNULDeviceFilename_Succeeds)
{
AZ::IO::FileReader fileReader(this->m_fileIo.get(), AZ::IO::SystemFile::GetNullFilename());
AZ::IO::FixedMaxPath filePath;
EXPECT_TRUE(fileReader.GetFilePath(filePath));
AZ::IO::FixedMaxPath nulFilename{ AZ::IO::SystemFile::GetNullFilename() };
if (this->m_fileIo)
{
EXPECT_TRUE(this->m_fileIo->ResolvePath(nulFilename, nulFilename));
}
EXPECT_EQ(nulFilename, filePath);
}
} // namespace UnitTest

@ -37,6 +37,7 @@ set(FILES
FileIOBaseTestTypes.h FileIOBaseTestTypes.h
Geometry2DUtils.cpp Geometry2DUtils.cpp
Interface.cpp Interface.cpp
IO/FileReaderTests.cpp
IO/Path/PathTests.cpp IO/Path/PathTests.cpp
IPC.cpp IPC.cpp
Jobs.cpp Jobs.cpp

@ -10,17 +10,12 @@
# Only 'xcb' and 'wayland' are recognized # Only 'xcb' and 'wayland' are recognized
if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb") if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
find_library(XCB_LIBRARY xcb)
find_library(XCB_XKB_LIBRARY xcb-xkb)
find_library(XKBCOMMON_LIBRARY xkbcommon)
find_library(XKBCOMMON_X11_LIBRARY xkbcommon-x11)
set(LY_BUILD_DEPENDENCIES set(LY_BUILD_DEPENDENCIES
PRIVATE PRIVATE
${XCB_LIBRARY} 3rdParty::X11::xcb
${XKBCOMMON_LIBRARY} 3rdParty::X11::xcb_xkb
${XKBCOMMON_X11_LIBRARY} 3rdParty::X11::xkbcommon
${XCB_XKB_LIBRARY} 3rdParty::X11::xkbcommon_X11
) )
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB) set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)

@ -28,6 +28,7 @@
#include <AzToolsFramework/ToolsComponents/TransformComponent.h> #include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h> #include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h> #include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
#include <AzToolsFramework/Slice/SliceMetadataEntityContextComponent.h> #include <AzToolsFramework/Slice/SliceMetadataEntityContextComponent.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponent.h> #include <AzToolsFramework/Prefab/PrefabSystemComponent.h>
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h> #include <AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h>
@ -248,6 +249,7 @@ namespace AzToolsFramework
components.insert(components.end(), { components.insert(components.end(), {
azrtti_typeid<EditorEntityContextComponent>(), azrtti_typeid<EditorEntityContextComponent>(),
azrtti_typeid<Components::EditorEntityUiSystemComponent>(), azrtti_typeid<Components::EditorEntityUiSystemComponent>(),
azrtti_typeid<FocusModeSystemComponent>(),
azrtti_typeid<SliceMetadataEntityContextComponent>(), azrtti_typeid<SliceMetadataEntityContextComponent>(),
azrtti_typeid<Prefab::PrefabSystemComponent>(), azrtti_typeid<Prefab::PrefabSystemComponent>(),
azrtti_typeid<EditorEntityFixupComponent>(), azrtti_typeid<EditorEntityFixupComponent>(),

@ -138,7 +138,13 @@ namespace AzToolsFramework
m_indexMap[row] = index; m_indexMap[row] = index;
m_rowMap[index] = row; m_rowMap[index] = row;
++row; ++row;
++m_displayedItemsCounter;
// We only want to increase the displayed counter if it is a parent (Source)
// so we don't cut children entries.
if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source)
{
++m_displayedItemsCounter;
}
} }
if (model->hasChildren(index)) if (model->hasChildren(index))

@ -29,20 +29,20 @@ namespace AzToolsFramework
{ {
AssetBrowserTableView::AssetBrowserTableView(QWidget* parent) AssetBrowserTableView::AssetBrowserTableView(QWidget* parent)
: AzQtComponents::TableView(parent) : AzQtComponents::TableView(parent)
, m_delegate(new EntryDelegate(this)) , m_delegate(new SearchEntryDelegate(this))
{ {
setSortingEnabled(true); setSortingEnabled(false);
setItemDelegate(m_delegate); setItemDelegate(m_delegate);
setRootIsDecorated(false); setRootIsDecorated(false);
//Styling the header aligning text to the left and using a bold font. //Styling the header aligning text to the left and using a bold font.
header()->setDefaultAlignment(Qt::AlignLeft); header()->setDefaultAlignment(Qt::AlignLeft);
header()->setStyleSheet("QHeaderView { font-weight: bold; }"); header()->setStyleSheet("QHeaderView { font-weight: bold; };");
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
setMouseTracking(true); setMouseTracking(true);
setSortingEnabled(false);
setSelectionMode(QAbstractItemView::SingleSelection); setSelectionMode(QAbstractItemView::SingleSelection);
connect(this, &AzQtComponents::TableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu); connect(this, &AzQtComponents::TableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu);
@ -67,6 +67,8 @@ namespace AzToolsFramework
header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch); header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch); header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
header()->setSortIndicatorShown(false);
header()->setSectionsClickable(false);
} }
void AssetBrowserTableView::SetName(const QString& name) void AssetBrowserTableView::SetName(const QString& name)

@ -26,7 +26,7 @@ namespace AzToolsFramework
class AssetBrowserEntry; class AssetBrowserEntry;
class AssetBrowserTableModel; class AssetBrowserTableModel;
class AssetBrowserFilterModel; class AssetBrowserFilterModel;
class EntryDelegate; class SearchEntryDelegate;
class AssetBrowserTableView //! Table view that displays the asset browser entries in a list. class AssetBrowserTableView //! Table view that displays the asset browser entries in a list.
: public AzQtComponents::TableView : public AzQtComponents::TableView
@ -67,9 +67,9 @@ namespace AzToolsFramework
private: private:
QString m_name; QString m_name;
QPointer<AssetBrowserTableModel> m_tableModel = nullptr; QPointer<AssetBrowserTableModel> m_tableModel;
QPointer<AssetBrowserFilterModel> m_sourceFilterModel = nullptr; QPointer<AssetBrowserFilterModel> m_sourceFilterModel;
EntryDelegate* m_delegate = nullptr; SearchEntryDelegate* m_delegate = nullptr;
private Q_SLOTS: private Q_SLOTS:
void OnContextMenu(const QPoint& point); void OnContextMenu(const QPoint& point);

@ -11,12 +11,13 @@
#include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h> #include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h> #include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <AzToolsFramework/AssetBrowser/Views/EntryDelegate.h> #include <AzToolsFramework/AssetBrowser/Views/EntryDelegate.h>
#include <AzCore/Utils/Utils.h>
#include <AzQtComponents/Components/StyledBusyLabel.h> #include <AzQtComponents/Components/StyledBusyLabel.h>
#include <QApplication> #include <QApplication>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer<QBrushData,QBrushDataPointerDeleter>' needs to have dll-interface to be used by clients of class 'QBrush' AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer<QBrushData,QBrushDataPointerDeleter>' needs to have dll-interface to be used by clients of class 'QBrush'
// 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning) // 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning)
#include <QAbstractItemView>
#include <QPainter> #include <QPainter>
AZ_POP_DISABLE_WARNING AZ_POP_DISABLE_WARNING
@ -24,8 +25,13 @@ namespace AzToolsFramework
{ {
namespace AssetBrowser namespace AssetBrowser
{ {
const int ENTRY_SPACING_LEFT_PIXELS = 8; static constexpr const char* TreeIconPathFirst = "Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg";
const int ENTRY_ICON_MARGIN_LEFT_PIXELS = 2; static constexpr const char* TreeIconPathMiddle = "Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg";
static constexpr const char* TreeIconPathLast = "Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg";
static constexpr const char* TreeIconPathOneChild = "Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg";
const int EntrySpacingLeftPixels = 8;
const int EntryIconMarginLeftPixels = 2;
EntryDelegate::EntryDelegate(QWidget* parent) EntryDelegate::EntryDelegate(QWidget* parent)
: QStyledItemDelegate(parent) : QStyledItemDelegate(parent)
@ -62,7 +68,7 @@ namespace AzToolsFramework
// Draw main entry thumbnail. // Draw main entry thumbnail.
QRect remainingRect(option.rect); QRect remainingRect(option.rect);
remainingRect.adjust(ENTRY_ICON_MARGIN_LEFT_PIXELS, 0, 0, 0); // bump it rightwards to give some margin to the icon. remainingRect.adjust(EntryIconMarginLeftPixels, 0, 0, 0); // bump it rightwards to give some margin to the icon.
QSize iconSize(m_iconSize, m_iconSize); QSize iconSize(m_iconSize, m_iconSize);
// Note that the thumbnail might actually be smaller than the row if theres a lot of padding or font size // Note that the thumbnail might actually be smaller than the row if theres a lot of padding or font size
@ -89,7 +95,7 @@ namespace AzToolsFramework
} }
remainingRect.adjust(thumbX, 0, 0, 0); // bump it to the right by the size of the thumbnail remainingRect.adjust(thumbX, 0, 0, 0); // bump it to the right by the size of the thumbnail
remainingRect.adjust(ENTRY_SPACING_LEFT_PIXELS, 0, 0, 0); // bump it to the right by the spacing. remainingRect.adjust(EntrySpacingLeftPixels, 0, 0, 0); // bump it to the right by the spacing.
} }
QString displayString = index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name) QString displayString = index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name)
? qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Name))) ? qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Name)))
@ -148,7 +154,162 @@ namespace AzToolsFramework
return m_iconSize; return m_iconSize;
} }
} // namespace Thumbnailer SearchEntryDelegate::SearchEntryDelegate(QWidget* parent)
: EntryDelegate(parent)
{
LoadBranchPixMaps();
}
void SearchEntryDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
auto data = index.data(AssetBrowserModel::Roles::EntryRole);
if (data.canConvert<const AssetBrowserEntry*>())
{
bool isEnabled = (option.state & QStyle::State_Enabled) != 0;
bool isSelected = (option.state & QStyle::State_Selected) != 0;
QStyle* style = option.widget ? option.widget->style() : QApplication::style();
// draw the background
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, option.widget);
// Draw main entry thumbnail.
QRect remainingRect(option.rect);
QSize iconSize(m_iconSize, m_iconSize);
// Note that the thumbnail might actually be smaller than the row if theres a lot of padding or font size
// so it needs to center vertically with padding in that case:
QPoint iconTopLeft;
QPoint branchIconTopLeft = QPoint();
auto entry = qvariant_cast<const AssetBrowserEntry*>(data);
auto sourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(entry);
//If it is a SourceEntry or it is not the column name we don't want to add space for the branch Icon
if (sourceEntry || index.column() != aznumeric_cast<int>(AssetBrowserEntry::Column::Name))
{
remainingRect.adjust(EntryIconMarginLeftPixels, 0, 0, 0); // bump it rightwards to give some margin to the icon.
iconTopLeft = QPoint(remainingRect.x(), remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
}
else
{
remainingRect.adjust(EntryIconMarginLeftPixels + m_iconSize, 0, 0, 0); // bump it rightwards to give some margin to the icon.
iconTopLeft = QPoint(remainingRect.x() / 2 + m_iconSize, remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
branchIconTopLeft = QPoint((remainingRect.x() / 2) - 2, remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
}
QPalette actualPalette(option.palette);
if (index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name))
{
int thumbX = DrawThumbnail(painter, iconTopLeft, iconSize, entry->GetThumbnailKey());
if (sourceEntry)
{
if (m_showSourceControl)
{
DrawThumbnail(painter, iconTopLeft, iconSize, sourceEntry->GetSourceControlThumbnailKey());
}
// sources with no children should be greyed out.
if (sourceEntry->GetChildCount() == 0)
{
isEnabled = false; // draw in disabled style.
actualPalette.setCurrentColorGroup(QPalette::Disabled);
}
}
else
{
//Get the indexes above and below our entry to see what type are they.
QAbstractItemView* view = qobject_cast<QAbstractItemView*>(option.styleObject);
const QAbstractItemModel* viewModel = view->model();
const QModelIndex indexBelow = viewModel->index(index.row() + 1, index.column());
const QModelIndex indexAbove = viewModel->index(index.row() - 1, index.column());
auto aboveEntry = qvariant_cast<const AssetBrowserEntry*>(indexBelow.data(AssetBrowserModel::Roles::EntryRole));
auto belowEntry = qvariant_cast<const AssetBrowserEntry*>(indexAbove.data(AssetBrowserModel::Roles::EntryRole));
auto aboveSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(aboveEntry);
auto belowSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(belowEntry);
// if current index is the last entry in the view
// or the index above it is a Source Entry and
// the index below is invalid or is valid but it is also a source entry
// then the current index is the only child.
if (index.row() == viewModel->rowCount() - 1 ||
(indexBelow.isValid() && aboveSourceEntry &&
(!indexAbove.isValid() || (indexAbove.isValid() && belowSourceEntry))))
{
DrawBranchPixMap(EntryBranchType::OneChild, painter, branchIconTopLeft, iconSize); // Draw One Child Icon
}
else if (indexBelow.isValid() && aboveSourceEntry) // The index above is a source entry
{
DrawBranchPixMap(EntryBranchType::Last, painter, branchIconTopLeft, iconSize); // Draw First child Icon
}
else if (indexAbove.isValid() && belowSourceEntry) // The index below is a source entry
{
DrawBranchPixMap(EntryBranchType::First, painter, branchIconTopLeft, iconSize); // Draw Last Child Icon
}
else //the index above and below are also child entries
{
DrawBranchPixMap(EntryBranchType::Middle, painter, branchIconTopLeft, iconSize); // Draw Default child Icon.
}
}
remainingRect.adjust(thumbX, 0, 0, 0); // bump it to the right by the size of the thumbnail
remainingRect.adjust(EntrySpacingLeftPixels, 0, 0, 0); // bump it to the right by the spacing.
}
QString displayString = index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name)
? qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Name)))
: qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Path)));
style->drawItemText(
painter, remainingRect, option.displayAlignment, actualPalette, isEnabled, displayString,
isSelected ? QPalette::HighlightedText : QPalette::Text);
}
}
void SearchEntryDelegate::LoadBranchPixMaps()
{
AZ::IO::BasicPath<AZ::IO::FixedMaxPathString> absoluteIconPath;
for (int branchType = EntryBranchType::First; branchType != EntryBranchType::Count; ++branchType)
{
QPixmap pixmap;
switch (branchType)
{
case AzToolsFramework::AssetBrowser::EntryBranchType::First:
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathFirst;
break;
case AzToolsFramework::AssetBrowser::EntryBranchType::Middle:
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathMiddle;
break;
case AzToolsFramework::AssetBrowser::EntryBranchType::Last:
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathLast;
break;
case AzToolsFramework::AssetBrowser::EntryBranchType::OneChild:
default:
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathOneChild;
break;
}
bool pixmapLoadedSuccess = pixmap.load(absoluteIconPath.c_str());
AZ_Assert(pixmapLoadedSuccess, "Error loading Branch Icons in SearchEntryDelegate");
m_branchIcons[static_cast<EntryBranchType>(branchType)] = pixmap;
}
}
void SearchEntryDelegate::DrawBranchPixMap(
EntryBranchType branchType, QPainter* painter, const QPoint& point, const QSize& size) const
{
const QPixmap& pixmap = m_branchIcons[branchType];
pixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
const QSize sizeDelta = size - pixmap.size();
const QPoint pointDelta = QPoint(sizeDelta.width() / 2, sizeDelta.height() / 2);
painter->drawPixmap(point + pointDelta, pixmap);
}
} // namespace AssetBrowser
} // namespace AzToolsFramework } // namespace AzToolsFramework
#include "AssetBrowser/Views/moc_EntryDelegate.cpp" #include "AssetBrowser/Views/moc_EntryDelegate.cpp"

@ -27,9 +27,19 @@ namespace AzToolsFramework
{ {
namespace AssetBrowser namespace AssetBrowser
{ {
//! Type of branch icon the delegate should paint.
enum EntryBranchType
{
First,
Middle,
Last,
OneChild,
Count
};
class AssetBrowserFilterModel; class AssetBrowserFilterModel;
//! EntryDelegate draws a single item in AssetBrowser //! EntryDelegate draws a single item in AssetBrowser.
class EntryDelegate class EntryDelegate
: public QStyledItemDelegate : public QStyledItemDelegate
{ {
@ -52,5 +62,23 @@ namespace AzToolsFramework
//! Draw a thumbnail and return its width //! Draw a thumbnail and return its width
int DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const; int DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const;
}; };
//! SearchEntryDelegate draws a single item in AssetBrowserTableView.
class SearchEntryDelegate
: public EntryDelegate
{
Q_OBJECT
public:
explicit SearchEntryDelegate(QWidget* parent = nullptr);
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
private:
void LoadBranchPixMaps();
void DrawBranchPixMap(EntryBranchType branchType, QPainter* painter, const QPoint& point, const QSize& size) const;
private:
QMap<EntryBranchType, QPixmap> m_branchIcons;
};
} // namespace AssetBrowser } // namespace AssetBrowser
} // namespace AzToolsFramework } // namespace AzToolsFramework

@ -22,6 +22,7 @@
#include <AzToolsFramework/Entity/EditorEntityModelComponent.h> #include <AzToolsFramework/Entity/EditorEntityModelComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySearchComponent.h> #include <AzToolsFramework/Entity/EditorEntitySearchComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySortComponent.h> #include <AzToolsFramework/Entity/EditorEntitySortComponent.h>
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
#include <AzToolsFramework/PropertyTreeEditor/PropertyTreeEditorComponent.h> #include <AzToolsFramework/PropertyTreeEditor/PropertyTreeEditorComponent.h>
#include <AzToolsFramework/Render/EditorIntersectorComponent.h> #include <AzToolsFramework/Render/EditorIntersectorComponent.h>
#include <AzToolsFramework/Slice/SliceDependencyBrowserComponent.h> #include <AzToolsFramework/Slice/SliceDependencyBrowserComponent.h>
@ -69,6 +70,7 @@ namespace AzToolsFramework
Components::EditorSelectionAccentSystemComponent::CreateDescriptor(), Components::EditorSelectionAccentSystemComponent::CreateDescriptor(),
EditorEntityContextComponent::CreateDescriptor(), EditorEntityContextComponent::CreateDescriptor(),
EditorEntityFixupComponent::CreateDescriptor(), EditorEntityFixupComponent::CreateDescriptor(),
FocusModeSystemComponent::CreateDescriptor(),
SliceMetadataEntityContextComponent::CreateDescriptor(), SliceMetadataEntityContextComponent::CreateDescriptor(),
SliceRequestComponent::CreateDescriptor(), SliceRequestComponent::CreateDescriptor(),
Prefab::PrefabSystemComponent::CreateDescriptor(), Prefab::PrefabSystemComponent::CreateDescriptor(),

@ -0,0 +1,39 @@
/*
* 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>
namespace AzToolsFramework
{
//! FocusModeInterface
//! Interface to handle the Editor Focus Mode.
class FocusModeInterface
{
public:
AZ_RTTI(FocusModeInterface, "{437243B0-F86B-422F-B7B8-4A21CC000702}");
//! Sets the root entity the Editor should focus on.
//! The Editor will only allow the user to select entities that are descendants of the EntityId provided.
//! @param entityId The entityId that will become the new focus root.
virtual void SetFocusRoot(AZ::EntityId entityId) = 0;
//! Clears the Editor focus, allowing the user to select the whole level again.
virtual void ClearFocusRoot() = 0;
//! Returns the entity id of the root of the current Editor focus.
//! @return The entity id of the root of the Editor focus, or an invalid entity id if no focus is set.
virtual AZ::EntityId GetFocusRoot() = 0;
//! Returns whether the entity id provided is part of the focused sub-tree.
virtual bool IsInFocusSubTree(AZ::EntityId entityId) = 0;
};
} // namespace AzToolsFramework

@ -0,0 +1,92 @@
/*
* 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/Component/TransformBus.h>
#include <AzToolsFramework/API/ViewportEditorModeTrackerInterface.h>
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
namespace AzToolsFramework
{
bool IsInFocusSubTree(AZ::EntityId entityId, AZ::EntityId focusRootId)
{
if (entityId == AZ::EntityId())
{
return false;
}
if (entityId == focusRootId)
{
return true;
}
AZ::EntityId parentId;
AZ::TransformBus::EventResult(parentId, entityId, &AZ::TransformInterface::GetParentId);
return IsInFocusSubTree(parentId, focusRootId);
}
void FocusModeSystemComponent::Init()
{
}
void FocusModeSystemComponent::Activate()
{
AZ::Interface<FocusModeInterface>::Register(this);
}
void FocusModeSystemComponent::Deactivate()
{
AZ::Interface<FocusModeInterface>::Unregister(this);
}
void FocusModeSystemComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context)
{
}
void FocusModeSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("EditorFocusMode"));
}
void FocusModeSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
{
}
void FocusModeSystemComponent::GetIncompatibleServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
}
void FocusModeSystemComponent::SetFocusRoot(AZ::EntityId entityId)
{
m_focusRoot = entityId;
// TODO - If m_focusRoot != AZ::EntityId(), activate focus mode via ViewportEditorModeTrackerInterface; else, deactivate focus mode
}
void FocusModeSystemComponent::ClearFocusRoot()
{
SetFocusRoot(AZ::EntityId());
}
AZ::EntityId FocusModeSystemComponent::GetFocusRoot()
{
return m_focusRoot;
}
bool FocusModeSystemComponent::IsInFocusSubTree(AZ::EntityId entityId)
{
if (m_focusRoot == AZ::EntityId())
{
return true;
}
return AzToolsFramework::IsInFocusSubTree(entityId, m_focusRoot);
}
} // namespace AzToolsFramework

@ -0,0 +1,51 @@
/*
* 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/FocusMode/FocusModeInterface.h>
namespace AzToolsFramework
{
bool IsInFocusSubTree(AZ::EntityId entityId, AZ::EntityId focusRootId);
//! System Component to handle the Editor Focus Mode system
class FocusModeSystemComponent final
: public AZ::Component
, private FocusModeInterface
{
public:
AZ_COMPONENT(FocusModeSystemComponent, "{6CE522FE-2057-4794-BD05-61E04BD8EA30}");
FocusModeSystemComponent() = default;
virtual ~FocusModeSystemComponent() = default;
// AZ::Component overrides ...
void Init() override;
void Activate() override;
void Deactivate() override;
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
// FocusModeInterface overrides ...
void SetFocusRoot(AZ::EntityId entityId) override;
void ClearFocusRoot() override;
AZ::EntityId GetFocusRoot() override;
bool IsInFocusSubTree(AZ::EntityId entityId) override;
private:
AZ::EntityId m_focusRoot;
};
} // namespace AzToolsFramework

@ -0,0 +1,102 @@
/*
* 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/Prefab/PrefabFocusHandler.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
namespace AzToolsFramework::Prefab
{
PrefabFocusHandler::PrefabFocusHandler()
{
m_instanceEntityMapperInterface = AZ::Interface<InstanceEntityMapperInterface>::Get();
AZ_Assert(
m_instanceEntityMapperInterface,
"Prefab - PrefabFocusHandler - "
"Instance Entity Mapper Interface could not be found. "
"Check that it is being correctly initialized.");
AZ::Interface<PrefabFocusInterface>::Register(this);
}
PrefabFocusHandler::~PrefabFocusHandler()
{
AZ::Interface<PrefabFocusInterface>::Unregister(this);
}
PrefabFocusOperationResult PrefabFocusHandler::FocusOnOwningPrefab(AZ::EntityId entityId)
{
InstanceOptionalReference focusedInstance;
if (entityId == AZ::EntityId())
{
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
if(!prefabEditorEntityOwnershipInterface)
{
return AZ::Failure(AZStd::string("Could not focus on root prefab instance - internal error "
"(PrefabEditorEntityOwnershipInterface unavailable)."));
}
focusedInstance = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
}
else
{
focusedInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
}
if (!focusedInstance.has_value())
{
return AZ::Failure(AZStd::string(
"Prefab Focus Handler: Couldn't find owning instance of entityId provided."));
}
m_focusedInstance = focusedInstance;
m_focusedTemplateId = focusedInstance->get().GetTemplateId();
FocusModeInterface* focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
if (focusModeInterface)
{
focusModeInterface->SetFocusRoot(focusedInstance->get().GetContainerEntityId());
}
return AZ::Success();
}
TemplateId PrefabFocusHandler::GetFocusedPrefabTemplateId()
{
return m_focusedTemplateId;
}
InstanceOptionalReference PrefabFocusHandler::GetFocusedPrefabInstance()
{
return m_focusedInstance;
}
bool PrefabFocusHandler::IsOwningPrefabBeingFocused(AZ::EntityId entityId)
{
if (!m_focusedInstance.has_value())
{
// PrefabFocusHandler has not been initialized yet.
return false;
}
if (entityId == AZ::EntityId())
{
return false;
}
InstanceOptionalReference instance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
return instance.has_value() && (&instance->get() == &m_focusedInstance->get());
}
} // namespace AzToolsFramework::Prefab

@ -0,0 +1,44 @@
/*
* 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/Memory/SystemAllocator.h>
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
#include <AzToolsFramework/Prefab/Template/Template.h>
namespace AzToolsFramework::Prefab
{
class InstanceEntityMapperInterface;
//! Handles Prefab Focus mode, determining which prefab file entity changes will target.
class PrefabFocusHandler final
: private PrefabFocusInterface
{
public:
AZ_CLASS_ALLOCATOR(PrefabFocusHandler, AZ::SystemAllocator, 0);
PrefabFocusHandler();
~PrefabFocusHandler();
// PrefabFocusInterface override ...
PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override;
TemplateId GetFocusedPrefabTemplateId() override;
InstanceOptionalReference GetFocusedPrefabInstance() override;
bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) override;
private:
InstanceOptionalReference m_focusedInstance;
TemplateId m_focusedTemplateId;
InstanceEntityMapperInterface* m_instanceEntityMapperInterface;
};
} // namespace AzToolsFramework::Prefab

@ -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 <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/Template/Template.h>
namespace AzToolsFramework::Prefab
{
using PrefabFocusOperationResult = AZ::Outcome<void, AZStd::string>;
//! Interface to handle operations related to the Prefab Focus system.
class PrefabFocusInterface
{
public:
AZ_RTTI(PrefabFocusInterface, "{F3CFA37B-5FD8-436A-9C30-60EB54E350E1}");
//! Set the focused prefab instance to the owning instance of the entityId provided.
//! @param entityId The entityId of the entity whose owning instance we want the prefab system to focus on.
virtual PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) = 0;
//! Returns the template id of the instance the prefab system is focusing on.
virtual TemplateId GetFocusedPrefabTemplateId() = 0;
//! Returns a reference to the instance the prefab system is focusing on.
virtual InstanceOptionalReference GetFocusedPrefabInstance() = 0;
//! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants.
//! @param entityId The entityId of the queried entity.
//! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise.
virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) = 0;
};
} // namespace AzToolsFramework::Prefab

@ -13,6 +13,7 @@
#include <AzCore/std/string/string_view.h> #include <AzCore/std/string/string_view.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h> #include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/PrefabFocusHandler.h>
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h> #include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h> #include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
#include <AzToolsFramework/Prefab/PrefabUndoCache.h> #include <AzToolsFramework/Prefab/PrefabUndoCache.h>
@ -189,6 +190,9 @@ namespace AzToolsFramework
PrefabLoaderInterface* m_prefabLoaderInterface = nullptr; PrefabLoaderInterface* m_prefabLoaderInterface = nullptr;
PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr; PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr;
// Handles the Prefab Focus API that determines what prefab is being edited.
PrefabFocusHandler m_prefabFocusHandler;
// Caches entity states for undo/redo purposes // Caches entity states for undo/redo purposes
PrefabUndoCache m_prefabUndoCache; PrefabUndoCache m_prefabUndoCache;

@ -369,7 +369,7 @@ namespace AzToolsFramework
// A counter for generating unique Link Ids. // A counter for generating unique Link Ids.
AZStd::atomic<LinkId> m_linkIdCounter = 0u; AZStd::atomic<LinkId> m_linkIdCounter = 0u;
// Used for finding the owning instance of an arbitrary entity // Used for finding the owning instance of an arbitrary entity.
InstanceEntityMapper m_instanceEntityMapper; InstanceEntityMapper m_instanceEntityMapper;
// Used for finding the Instances owned by an arbitrary Template. // Used for finding the Instances owned by an arbitrary Template.
@ -378,16 +378,16 @@ namespace AzToolsFramework
// Used for loading/saving Prefab Template files. // Used for loading/saving Prefab Template files.
PrefabLoader m_prefabLoader; PrefabLoader m_prefabLoader;
// Handler the public Prefab API used by UI and scripting // Handles the public Prefab API used by UI and scripting.
PrefabPublicHandler m_prefabPublicHandler; PrefabPublicHandler m_prefabPublicHandler;
// Used for updating Instances of Prefab Template. // Used for updating Instances of Prefab Template.
InstanceUpdateExecutor m_instanceUpdateExecutor; InstanceUpdateExecutor m_instanceUpdateExecutor;
// Used for updating Templates when Instances are modified // Used for updating Templates when Instances are modified.
InstanceToTemplatePropagator m_instanceToTemplatePropagator; InstanceToTemplatePropagator m_instanceToTemplatePropagator;
// Handler of the public Prefab requests // Handler of the public Prefab requests.
PrefabPublicRequestHandler m_prefabPublicRequestHandler; PrefabPublicRequestHandler m_prefabPublicRequestHandler;
}; };
} // namespace Prefab } // namespace Prefab

@ -8,7 +8,6 @@
#include <AzToolsFramework/UI/Prefab/LevelRootUiHandler.h> #include <AzToolsFramework/UI/Prefab/LevelRootUiHandler.h>
#include <AzToolsFramework/UI/Prefab/PrefabEditInterface.h>
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h> #include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
#include <AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx> #include <AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx>
@ -24,14 +23,6 @@ namespace AzToolsFramework
LevelRootUiHandler::LevelRootUiHandler() LevelRootUiHandler::LevelRootUiHandler()
{ {
m_prefabEditInterface = AZ::Interface<Prefab::PrefabEditInterface>::Get();
if (m_prefabEditInterface == nullptr)
{
AZ_Assert(false, "LevelRootUiHandler - could not get PrefabEditInterface on LevelRootUiHandler construction.");
return;
}
m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get(); m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
if (m_prefabPublicInterface == nullptr) if (m_prefabPublicInterface == nullptr)

@ -14,7 +14,6 @@ namespace AzToolsFramework
{ {
namespace Prefab namespace Prefab
{ {
class PrefabEditInterface;
class PrefabPublicInterface; class PrefabPublicInterface;
}; };
@ -36,7 +35,6 @@ namespace AzToolsFramework
void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
private: private:
Prefab::PrefabEditInterface* m_prefabEditInterface = nullptr;
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr; Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
static constexpr int m_levelRootBorderThickness = 1; static constexpr int m_levelRootBorderThickness = 1;

@ -1,43 +0,0 @@
/*
* 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>
namespace AzToolsFramework
{
namespace Prefab
{
/*!
* PrefabEditInterface
* Interface to expose the API to Edit Prefabs in the Editor.
*/
class PrefabEditInterface
{
public:
AZ_RTTI(PrefabEditInterface, "{DABB1D43-3760-420E-9F1E-5104F0AFF167}");
/**
* Sets the prefab for the instance owning the entity provided as the prefab being edited.
* @param entityId The entity whose owning prefab should be edited.
*/
virtual void EditOwningPrefab(AZ::EntityId entityId) = 0;
/**
* Queries the Edit Manager to know if the provided entity is part of the prefab currently being edited.
* @param entityId The entity whose prefab editing state we want to query.
* @return True if the prefab owning this entity is being edited, false otherwise.
*/
virtual bool IsOwningPrefabBeingEdited(AZ::EntityId entityId) = 0;
};
} // namespace Prefab
} // namespace AzToolsFramework

@ -1,46 +0,0 @@
/*
* 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/UI/Prefab/PrefabEditManager.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AzToolsFramework
{
namespace Prefab
{
PrefabEditManager::PrefabEditManager()
{
m_prefabPublicInterface = AZ::Interface<PrefabPublicInterface>::Get();
if (m_prefabPublicInterface == nullptr)
{
AZ_Assert(false, "Prefab - could not get PrefabPublicInterface on PrefabEditManager construction.");
return;
}
AZ::Interface<PrefabEditInterface>::Register(this);
}
PrefabEditManager::~PrefabEditManager()
{
AZ::Interface<PrefabEditInterface>::Unregister(this);
}
void PrefabEditManager::EditOwningPrefab(AZ::EntityId entityId)
{
m_instanceBeingEdited = m_prefabPublicInterface->GetInstanceContainerEntityId(entityId);
}
bool PrefabEditManager::IsOwningPrefabBeingEdited(AZ::EntityId entityId)
{
AZ::EntityId containerEntity = m_prefabPublicInterface->GetInstanceContainerEntityId(entityId);
return m_instanceBeingEdited == containerEntity;
}
}
}

@ -1,40 +0,0 @@
/*
* 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/Memory/SystemAllocator.h>
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
#include <AzToolsFramework/UI/Prefab/PrefabEditInterface.h>
namespace AzToolsFramework
{
namespace Prefab
{
class PrefabEditManager final
: private PrefabEditInterface
{
public:
AZ_CLASS_ALLOCATOR(PrefabEditManager, AZ::SystemAllocator, 0);
PrefabEditManager();
~PrefabEditManager();
private:
// PrefabEditInterface...
void EditOwningPrefab(AZ::EntityId entityId) override;
bool IsOwningPrefabBeingEdited(AZ::EntityId entityId) override;
AZ::EntityId m_instanceBeingEdited;
PrefabPublicInterface* m_prefabPublicInterface;
};
}
}

@ -22,6 +22,7 @@
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h> #include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h> #include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
#include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h> #include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h> #include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
#include <AzToolsFramework/ToolsComponents/EditorLayerComponentBus.h> #include <AzToolsFramework/ToolsComponents/EditorLayerComponentBus.h>
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiInterface.h> #include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiInterface.h>
@ -57,9 +58,9 @@ namespace AzToolsFramework
{ {
EditorEntityUiInterface* PrefabIntegrationManager::s_editorEntityUiInterface = nullptr; EditorEntityUiInterface* PrefabIntegrationManager::s_editorEntityUiInterface = nullptr;
PrefabPublicInterface* PrefabIntegrationManager::s_prefabPublicInterface = nullptr; PrefabFocusInterface* PrefabIntegrationManager::s_prefabFocusInterface = nullptr;
PrefabEditInterface* PrefabIntegrationManager::s_prefabEditInterface = nullptr;
PrefabLoaderInterface* PrefabIntegrationManager::s_prefabLoaderInterface = nullptr; PrefabLoaderInterface* PrefabIntegrationManager::s_prefabLoaderInterface = nullptr;
PrefabPublicInterface* PrefabIntegrationManager::s_prefabPublicInterface = nullptr;
PrefabSystemComponentInterface* PrefabIntegrationManager::s_prefabSystemComponentInterface = nullptr; PrefabSystemComponentInterface* PrefabIntegrationManager::s_prefabSystemComponentInterface = nullptr;
const AZStd::string PrefabIntegrationManager::s_prefabFileExtension = ".prefab"; const AZStd::string PrefabIntegrationManager::s_prefabFileExtension = ".prefab";
@ -102,13 +103,6 @@ namespace AzToolsFramework
return; return;
} }
s_prefabEditInterface = AZ::Interface<PrefabEditInterface>::Get();
if (s_prefabEditInterface == nullptr)
{
AZ_Assert(false, "Prefab - could not get PrefabEditInterface on PrefabIntegrationManager construction.");
return;
}
s_prefabLoaderInterface = AZ::Interface<PrefabLoaderInterface>::Get(); s_prefabLoaderInterface = AZ::Interface<PrefabLoaderInterface>::Get();
if (s_prefabLoaderInterface == nullptr) if (s_prefabLoaderInterface == nullptr)
{ {
@ -123,6 +117,13 @@ namespace AzToolsFramework
return; return;
} }
s_prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
if (s_prefabFocusInterface == nullptr)
{
AZ_Assert(false, "Prefab - could not get PrefabFocusInterface on PrefabIntegrationManager construction.");
return;
}
EditorContextMenuBus::Handler::BusConnect(); EditorContextMenuBus::Handler::BusConnect();
PrefabInstanceContainerNotificationBus::Handler::BusConnect(); PrefabInstanceContainerNotificationBus::Handler::BusConnect();
AZ::Interface<PrefabIntegrationInterface>::Register(this); AZ::Interface<PrefabIntegrationInterface>::Register(this);
@ -224,7 +225,7 @@ namespace AzToolsFramework
// Edit Prefab // Edit Prefab
if (prefabWipFeaturesEnabled) if (prefabWipFeaturesEnabled)
{ {
bool beingEdited = s_prefabEditInterface->IsOwningPrefabBeingEdited(selectedEntity); bool beingEdited = s_prefabFocusInterface->IsOwningPrefabBeingFocused(selectedEntity);
if (!beingEdited) if (!beingEdited)
{ {
@ -428,7 +429,7 @@ namespace AzToolsFramework
void PrefabIntegrationManager::ContextMenu_EditPrefab(AZ::EntityId containerEntity) void PrefabIntegrationManager::ContextMenu_EditPrefab(AZ::EntityId containerEntity)
{ {
s_prefabEditInterface->EditOwningPrefab(containerEntity); s_prefabFocusInterface->FocusOnOwningPrefab(containerEntity);
} }
void PrefabIntegrationManager::ContextMenu_SavePrefab(AZ::EntityId containerEntity) void PrefabIntegrationManager::ContextMenu_SavePrefab(AZ::EntityId containerEntity)

@ -17,7 +17,7 @@
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h> #include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h> #include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
#include <AzToolsFramework/UI/Prefab/LevelRootUiHandler.h> #include <AzToolsFramework/UI/Prefab/LevelRootUiHandler.h>
#include <AzToolsFramework/UI/Prefab/PrefabEditManager.h>
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationBus.h> #include <AzToolsFramework/UI/Prefab/PrefabIntegrationBus.h>
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h> #include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h>
#include <AzToolsFramework/UI/Prefab/PrefabUiHandler.h> #include <AzToolsFramework/UI/Prefab/PrefabUiHandler.h>
@ -28,7 +28,7 @@ namespace AzToolsFramework
{ {
namespace Prefab namespace Prefab
{ {
class PrefabFocusInterface;
class PrefabLoaderInterface; class PrefabLoaderInterface;
//! Structure for saving/retrieving user settings related to prefab workflows. //! Structure for saving/retrieving user settings related to prefab workflows.
@ -80,9 +80,6 @@ namespace AzToolsFramework
void ExecuteSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference) override; void ExecuteSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference) override;
private: private:
// Manages the Edit Mode UI for prefabs
PrefabEditManager m_prefabEditManager;
// Used to handle the UI for the level root // Used to handle the UI for the level root
LevelRootUiHandler m_levelRootUiHandler; LevelRootUiHandler m_levelRootUiHandler;
@ -135,13 +132,12 @@ namespace AzToolsFramework
AZStd::unique_ptr<QDialog> ConstructSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference); AZStd::unique_ptr<QDialog> ConstructSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference);
void SavePrefabsInDialog(QDialog* unsavedPrefabsDialog); void SavePrefabsInDialog(QDialog* unsavedPrefabsDialog);
static const AZStd::string s_prefabFileExtension; static const AZStd::string s_prefabFileExtension;
static EditorEntityUiInterface* s_editorEntityUiInterface; static EditorEntityUiInterface* s_editorEntityUiInterface;
static PrefabPublicInterface* s_prefabPublicInterface; static PrefabFocusInterface* s_prefabFocusInterface;
static PrefabEditInterface* s_prefabEditInterface;
static PrefabLoaderInterface* s_prefabLoaderInterface; static PrefabLoaderInterface* s_prefabLoaderInterface;
static PrefabPublicInterface* s_prefabPublicInterface;
static PrefabSystemComponentInterface* s_prefabSystemComponentInterface; static PrefabSystemComponentInterface* s_prefabSystemComponentInterface;
}; };
} }

@ -8,7 +8,7 @@
#include <AzToolsFramework/UI/Prefab/PrefabUiHandler.h> #include <AzToolsFramework/UI/Prefab/PrefabUiHandler.h>
#include <AzToolsFramework/UI/Prefab/PrefabEditInterface.h> #include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h> #include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
#include <AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx> #include <AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx>
@ -26,19 +26,17 @@ namespace AzToolsFramework
PrefabUiHandler::PrefabUiHandler() PrefabUiHandler::PrefabUiHandler()
{ {
m_prefabEditInterface = AZ::Interface<Prefab::PrefabEditInterface>::Get(); m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
if (m_prefabPublicInterface == nullptr)
if (m_prefabEditInterface == nullptr)
{ {
AZ_Assert(false, "PrefabUiHandler - could not get PrefabEditInterface on PrefabUiHandler construction."); AZ_Assert(false, "PrefabUiHandler - could not get PrefabPublicInterface on PrefabUiHandler construction.");
return; return;
} }
m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get(); m_prefabFocusInterface = AZ::Interface<Prefab::PrefabFocusInterface>::Get();
if (m_prefabFocusInterface == nullptr)
if (m_prefabPublicInterface == nullptr)
{ {
AZ_Assert(false, "PrefabUiHandler - could not get PrefabPublicInterface on PrefabUiHandler construction."); AZ_Assert(false, "PrefabUiHandler - could not get PrefabFocusInterface on PrefabUiHandler construction.");
return; return;
} }
} }
@ -83,7 +81,7 @@ namespace AzToolsFramework
QIcon PrefabUiHandler::GenerateItemIcon(AZ::EntityId entityId) const QIcon PrefabUiHandler::GenerateItemIcon(AZ::EntityId entityId) const
{ {
if (m_prefabEditInterface->IsOwningPrefabBeingEdited(entityId)) if (m_prefabFocusInterface->IsOwningPrefabBeingFocused(entityId))
{ {
return QIcon(m_prefabEditIconPath); return QIcon(m_prefabEditIconPath);
} }
@ -105,7 +103,7 @@ namespace AzToolsFramework
const bool hasVisibleChildren = index.data(EntityOutlinerListModel::ExpandedRole).value<bool>() && index.model()->hasChildren(index); const bool hasVisibleChildren = index.data(EntityOutlinerListModel::ExpandedRole).value<bool>() && index.model()->hasChildren(index);
QColor backgroundColor = m_prefabCapsuleColor; QColor backgroundColor = m_prefabCapsuleColor;
if (m_prefabEditInterface->IsOwningPrefabBeingEdited(entityId)) if (m_prefabFocusInterface->IsOwningPrefabBeingFocused(entityId))
{ {
backgroundColor = m_prefabCapsuleEditColor; backgroundColor = m_prefabCapsuleEditColor;
} }
@ -191,7 +189,7 @@ namespace AzToolsFramework
const bool isLastColumn = descendantIndex.column() == EntityOutlinerListModel::ColumnLockToggle; const bool isLastColumn = descendantIndex.column() == EntityOutlinerListModel::ColumnLockToggle;
QColor borderColor = m_prefabCapsuleColor; QColor borderColor = m_prefabCapsuleColor;
if (m_prefabEditInterface->IsOwningPrefabBeingEdited(entityId)) if (m_prefabFocusInterface->IsOwningPrefabBeingFocused(entityId))
{ {
borderColor = m_prefabCapsuleEditColor; borderColor = m_prefabCapsuleEditColor;
} }

@ -12,9 +12,10 @@
namespace AzToolsFramework namespace AzToolsFramework
{ {
namespace Prefab namespace Prefab
{ {
class PrefabEditInterface; class PrefabFocusInterface;
class PrefabPublicInterface; class PrefabPublicInterface;
}; };
@ -37,7 +38,7 @@ namespace AzToolsFramework
const QModelIndex& descendantIndex) const override; const QModelIndex& descendantIndex) const override;
private: private:
Prefab::PrefabEditInterface* m_prefabEditInterface = nullptr; Prefab::PrefabFocusInterface* m_prefabFocusInterface = nullptr;
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr; Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
static bool IsLastVisibleChild(const QModelIndex& parent, const QModelIndex& child); static bool IsLastVisibleChild(const QModelIndex& parent, const QModelIndex& child);

@ -3642,7 +3642,7 @@ namespace AzToolsFramework
} }
} }
void EditorTransformComponentSelection::OnViewportViewEntityChanged(const AZ::EntityId& newViewId) void EditorTransformComponentSelection::OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId)
{ {
AZ_PROFILE_FUNCTION(AzToolsFramework); AZ_PROFILE_FUNCTION(AzToolsFramework);
@ -3650,12 +3650,12 @@ namespace AzToolsFramework
// match the editor camera translation/orientation), record the entity id if we have // match the editor camera translation/orientation), record the entity id if we have
// a manipulator tracking it (entity id exists in m_entityIdManipulator lookups) // a manipulator tracking it (entity id exists in m_entityIdManipulator lookups)
// and remove it when recreating manipulators (see InitializeManipulators) // and remove it when recreating manipulators (see InitializeManipulators)
if (newViewId.IsValid()) if (viewEntityId.IsValid())
{ {
const auto entityIdLookupIt = m_entityIdManipulators.m_lookups.find(newViewId); const auto entityIdLookupIt = m_entityIdManipulators.m_lookups.find(viewEntityId);
if (entityIdLookupIt != m_entityIdManipulators.m_lookups.end()) if (entityIdLookupIt != m_entityIdManipulators.m_lookups.end())
{ {
m_editorCameraComponentEntityId = newViewId; m_editorCameraComponentEntityId = viewEntityId;
RegenerateManipulators(); RegenerateManipulators();
} }
} }

@ -270,7 +270,7 @@ namespace AzToolsFramework
void OnTransformChanged(const AZ::Transform& localTM, const AZ::Transform& worldTM) override; void OnTransformChanged(const AZ::Transform& localTM, const AZ::Transform& worldTM) override;
// Camera::EditorCameraNotificationBus overrides ... // Camera::EditorCameraNotificationBus overrides ...
void OnViewportViewEntityChanged(const AZ::EntityId& newViewId) override; void OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId) override;
// EditorContextVisibilityNotificationBus overrides ... // EditorContextVisibilityNotificationBus overrides ...
void OnEntityVisibilityChanged(bool visibility) override; void OnEntityVisibilityChanged(bool visibility) override;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save