Merge branch 'development' of https://github.com/o3de/o3de into daimini/FocusMode/breadcrumbs
This commit is contained in:
@@ -8098,7 +8098,7 @@
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM0_TOOLTIP">
|
||||
<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 id="COLOR_FROMVALUES_PARAM1_NAME">
|
||||
<source>COLOR_FROMVALUES_PARAM1_NAME</source>
|
||||
@@ -8107,7 +8107,7 @@
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM1_TOOLTIP">
|
||||
<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 id="COLOR_FROMVALUES_PARAM2_NAME">
|
||||
<source>COLOR_FROMVALUES_PARAM2_NAME</source>
|
||||
@@ -8116,7 +8116,7 @@
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM2_TOOLTIP">
|
||||
<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 id="COLOR_FROMVALUES_PARAM3_NAME">
|
||||
<source>COLOR_FROMVALUES_PARAM3_NAME</source>
|
||||
@@ -8125,7 +8125,7 @@
|
||||
</message>
|
||||
<message id="COLOR_FROMVALUES_PARAM3_TOOLTIP">
|
||||
<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>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -17,5 +17,14 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
AZ::AssetProcessorBatch
|
||||
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()
|
||||
|
||||
@@ -34,11 +34,13 @@ logger = logging.getLogger(__name__)
|
||||
targetProjects = ["AutomatedTesting"]
|
||||
|
||||
@pytest.fixture
|
||||
@pytest.mark.SUITE_sandbox
|
||||
def local_resources(request, workspace, ap_setup_fixture):
|
||||
ap_setup_fixture["tests_dir"] = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
@dataclass
|
||||
@pytest.mark.SUITE_sandbox
|
||||
class BlackboxAssetTest:
|
||||
test_name: str
|
||||
asset_folder: str
|
||||
@@ -338,9 +340,11 @@ blackbox_fbx_special_tests = [
|
||||
@pytest.mark.usefixtures("local_resources")
|
||||
@pytest.mark.parametrize("project", targetProjects)
|
||||
@pytest.mark.assetpipeline
|
||||
@pytest.mark.SUITE_sandbox
|
||||
class TestsFBX_AllPlatforms(object):
|
||||
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("blackbox_param", blackbox_fbx_tests)
|
||||
def test_FBXBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace,
|
||||
ap_setup_fixture, asset_processor, project,
|
||||
@@ -359,6 +363,7 @@ class TestsFBX_AllPlatforms(object):
|
||||
asset_processor, project, blackbox_param)
|
||||
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("blackbox_param", blackbox_fbx_special_tests)
|
||||
def test_FBXBlackboxTest_AssetInfoModified_AssetReprocessed_ResultInExpectedProducts(self,
|
||||
workspace, ap_setup_fixture,
|
||||
|
||||
@@ -207,12 +207,6 @@ namespace AZ
|
||||
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);
|
||||
|
||||
EBUS_EVENT_ID(m_id, EntityBus, OnEntityActivated, m_id);
|
||||
@@ -1320,6 +1314,19 @@ namespace AZ
|
||||
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
|
||||
// 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.
|
||||
static AZ::u32 GetProcessSignature();
|
||||
|
||||
/// @cond EXCLUDE_DOCS
|
||||
//! @deprecated Use the TransformBus to communicate with the TransformInterface.
|
||||
inline TransformInterface* GetTransform() const { return m_transform; }
|
||||
/// @endcond
|
||||
//! Gets the TransformInterface for the entity.
|
||||
//! @return The TransformInterface for the entity.
|
||||
TransformInterface* GetTransform() const;
|
||||
|
||||
//! Sorts an entity's components based on the dependencies between components.
|
||||
//! If all dependencies are met, the required services can be activated
|
||||
@@ -406,7 +405,7 @@ namespace AZ
|
||||
//! A cached pointer to the transform interface.
|
||||
//! We recommend using AZ::TransformBus and caching locally instead of accessing
|
||||
//! 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.
|
||||
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);
|
||||
}
|
||||
|
||||
SystemFile::SizeType SystemFile::Tell()
|
||||
SystemFile::SizeType SystemFile::Tell() const
|
||||
{
|
||||
return Platform::Tell(m_handle, this);
|
||||
}
|
||||
|
||||
bool SystemFile::Eof()
|
||||
bool SystemFile::Eof() const
|
||||
{
|
||||
return Platform::Eof(m_handle, this);
|
||||
}
|
||||
|
||||
@@ -72,9 +72,9 @@ namespace AZ
|
||||
/// Seek in current file.
|
||||
void Seek(SeekSizeType offset, SeekMode mode);
|
||||
/// Get the cursor position in the current file.
|
||||
SizeType Tell();
|
||||
SizeType Tell() const;
|
||||
/// Is the cursor at the end of the file?
|
||||
bool Eof();
|
||||
bool Eof() const;
|
||||
/// Get the time the file was last modified.
|
||||
AZ::u64 ModificationTime();
|
||||
/// 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("CreateUniformScale", &Transform::CreateUniformScale)->
|
||||
Method("CreateTranslation", &Transform::CreateTranslation)->
|
||||
Method("CreateLookAt", &Transform::CreateLookAt)->
|
||||
Method("ConstructFromValuesNumeric", &Internal::ConstructTransformFromValues);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <cerrno>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/FileReader.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/JSON/error/en.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,
|
||||
AZStd::vector<char>& scratchBuffer)
|
||||
{
|
||||
@@ -1236,7 +1125,7 @@ namespace AZ
|
||||
|
||||
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())
|
||||
{
|
||||
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/Path/Path.h>
|
||||
#include <AzCore/IO/TextStreamWriters.h>
|
||||
@@ -388,8 +390,36 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
const ConfigParserSettings& configParserSettings)
|
||||
{
|
||||
auto configPath = FindEngineRoot(registry) / filePath;
|
||||
IO::SystemFile configFile;
|
||||
if (!configFile.Open(configPath.c_str(), IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY))
|
||||
IO::FileReader configFile;
|
||||
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());
|
||||
return false;
|
||||
@@ -480,7 +510,7 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
AZ_Error("SettingsRegistryMergeUtils", false,
|
||||
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"("%.*s")" "\n", configFile.Name(), configBuffer.max_size(),
|
||||
R"("%.*s")" "\n", configPath.c_str(), configBuffer.max_size(),
|
||||
aznumeric_cast<int>(configBuffer.size()), configBuffer.data());
|
||||
configFileParsed = false;
|
||||
break;
|
||||
|
||||
@@ -155,6 +155,15 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
//! structure which is forwarded to the SettingsRegistryInterface MergeCommandLineArgument function
|
||||
//! The structure contains a functor which returns true if a character is a valid delimiter
|
||||
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
|
||||
//! 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.h
|
||||
IO/FileIOEventBus.h
|
||||
IO/FileReader.cpp
|
||||
IO/FileReader.h
|
||||
IO/IOUtils.h
|
||||
IO/IOUtils.cpp
|
||||
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
|
||||
Geometry2DUtils.cpp
|
||||
Interface.cpp
|
||||
IO/FileReaderTests.cpp
|
||||
IO/Path/PathTests.cpp
|
||||
IPC.cpp
|
||||
Jobs.cpp
|
||||
|
||||
@@ -116,6 +116,12 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
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;
|
||||
|
||||
@@ -498,6 +498,18 @@ QProgressBar::chunk {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
/************** Gems SubWidget **************/
|
||||
|
||||
#gemSubWidgetTitleLabel {
|
||||
color: #FFFFFF;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#gemSubWidgetTextLabel {
|
||||
color: #DDDDDD;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
/************** Gem Catalog (Inspector) **************/
|
||||
|
||||
#GemCatalogInspector {
|
||||
@@ -597,3 +609,20 @@ QProgressBar::chunk {
|
||||
#gemRepoInspector {
|
||||
background: #444444;
|
||||
}
|
||||
|
||||
/************** Gem Repo Inspector **************/
|
||||
|
||||
#gemRepoInspectorNameLabel {
|
||||
font-size: 18px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
#gemRepoInspectorBodyLabel {
|
||||
font-size: 12px;
|
||||
color: #DDDDDD;
|
||||
}
|
||||
|
||||
#gemRepoInspectorAddInfoTitleLabel {
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <GemCatalog/GemCatalogHeaderWidget.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
#include <QLabel>
|
||||
@@ -23,7 +24,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
m_layout = new QVBoxLayout();
|
||||
m_layout->setSpacing(0);
|
||||
m_layout->setMargin(0);
|
||||
m_layout->setMargin(5);
|
||||
m_layout->setAlignment(Qt::AlignTop);
|
||||
setLayout(m_layout);
|
||||
|
||||
@@ -41,74 +42,111 @@ namespace O3DE::ProjectManager
|
||||
hLayout->addWidget(closeButton);
|
||||
m_layout->addLayout(hLayout);
|
||||
|
||||
// enabled
|
||||
{
|
||||
m_enabledWidget = new QWidget();
|
||||
m_enabledWidget->setFixedWidth(s_width);
|
||||
m_layout->addWidget(m_enabledWidget);
|
||||
// added
|
||||
CreateGemSection( tr("Gem to be activated"), tr("Gems to be activated"), [=]
|
||||
{
|
||||
QVector<QModelIndex> gems;
|
||||
const QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/false);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
m_enabledWidget->setLayout(layout);
|
||||
// don't include gems that were already active because they were dependencies
|
||||
for (const QModelIndex& modelIndex : toBeAdded)
|
||||
{
|
||||
if (!GemModel::WasPreviouslyAddedDependency(modelIndex))
|
||||
{
|
||||
gems.push_back(modelIndex);
|
||||
}
|
||||
}
|
||||
return gems;
|
||||
});
|
||||
|
||||
m_enabledLabel = new QLabel();
|
||||
m_enabledLabel->setObjectName("GemCatalogCartOverlaySectionLabel");
|
||||
layout->addWidget(m_enabledLabel);
|
||||
m_enabledTagContainer = new TagContainerWidget();
|
||||
layout->addWidget(m_enabledTagContainer);
|
||||
}
|
||||
// removed
|
||||
CreateGemSection( tr("Gem to be deactivated"), tr("Gems to be deactivated"), [=]
|
||||
{
|
||||
QVector<QModelIndex> gems;
|
||||
const QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/false);
|
||||
|
||||
// disabled
|
||||
{
|
||||
m_disabledWidget = new QWidget();
|
||||
m_disabledWidget->setFixedWidth(s_width);
|
||||
m_layout->addWidget(m_disabledWidget);
|
||||
// don't include gems that are still active because they are dependencies
|
||||
for (const QModelIndex& modelIndex : toBeAdded)
|
||||
{
|
||||
if (!GemModel::IsAddedDependency(modelIndex))
|
||||
{
|
||||
gems.push_back(modelIndex);
|
||||
}
|
||||
}
|
||||
return gems;
|
||||
});
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
m_disabledWidget->setLayout(layout);
|
||||
// added dependencies
|
||||
CreateGemSection( tr("Dependency to be activated"), tr("Dependencies to be activated"), [=]
|
||||
{
|
||||
QVector<QModelIndex> dependencies;
|
||||
const QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true);
|
||||
|
||||
m_disabledLabel = new QLabel();
|
||||
m_disabledLabel->setObjectName("GemCatalogCartOverlaySectionLabel");
|
||||
layout->addWidget(m_disabledLabel);
|
||||
m_disabledTagContainer = new TagContainerWidget();
|
||||
layout->addWidget(m_disabledTagContainer);
|
||||
}
|
||||
// only include gems that are dependencies and not explicitly added
|
||||
for (const QModelIndex& modelIndex : toBeAdded)
|
||||
{
|
||||
if (GemModel::IsAddedDependency(modelIndex) && !GemModel::IsAdded(modelIndex))
|
||||
{
|
||||
dependencies.push_back(modelIndex);
|
||||
}
|
||||
}
|
||||
return dependencies;
|
||||
});
|
||||
|
||||
// removed dependencies
|
||||
CreateGemSection( tr("Dependency to be deactivated"), tr("Dependencies to be deactivated"), [=]
|
||||
{
|
||||
QVector<QModelIndex> dependencies;
|
||||
const QVector<QModelIndex> toBeRemoved = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true);
|
||||
|
||||
// don't include gems that were explicitly removed - those are listed in a different section
|
||||
for (const QModelIndex& modelIndex : toBeRemoved)
|
||||
{
|
||||
if (!GemModel::WasPreviouslyAdded(modelIndex))
|
||||
{
|
||||
dependencies.push_back(modelIndex);
|
||||
}
|
||||
}
|
||||
return dependencies;
|
||||
});
|
||||
|
||||
setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
|
||||
|
||||
Update();
|
||||
connect(gemModel, &GemModel::dataChanged, this, [=]
|
||||
{
|
||||
Update();
|
||||
});
|
||||
}
|
||||
|
||||
void CartOverlayWidget::Update()
|
||||
void CartOverlayWidget::CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices)
|
||||
{
|
||||
const QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeAdded();
|
||||
if (toBeAdded.isEmpty())
|
||||
{
|
||||
m_enabledWidget->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_enabledTagContainer->Update(ConvertFromModelIndices(toBeAdded));
|
||||
m_enabledLabel->setText(QString("%1 %2").arg(QString::number(toBeAdded.size()), tr("Gems to be enabled")));
|
||||
m_enabledWidget->show();
|
||||
}
|
||||
QWidget* widget = new QWidget();
|
||||
widget->setFixedWidth(s_width);
|
||||
m_layout->addWidget(widget);
|
||||
|
||||
const QVector<QModelIndex> toBeRemoved = m_gemModel->GatherGemsToBeRemoved();
|
||||
if (toBeRemoved.isEmpty())
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
widget->setLayout(layout);
|
||||
|
||||
QLabel* label = new QLabel();
|
||||
label->setObjectName("GemCatalogCartOverlaySectionLabel");
|
||||
layout->addWidget(label);
|
||||
|
||||
TagContainerWidget* tagContainer = new TagContainerWidget();
|
||||
layout->addWidget(tagContainer);
|
||||
|
||||
auto update = [=]()
|
||||
{
|
||||
m_disabledWidget->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_disabledTagContainer->Update(ConvertFromModelIndices(toBeRemoved));
|
||||
m_disabledLabel->setText(QString("%1 %2").arg(QString::number(toBeRemoved.size()), tr("Gems to be disabled")));
|
||||
m_disabledWidget->show();
|
||||
}
|
||||
const QVector<QModelIndex> tagIndices = getTagIndices();
|
||||
if (tagIndices.isEmpty())
|
||||
{
|
||||
widget->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
tagContainer->Update(ConvertFromModelIndices(tagIndices));
|
||||
label->setText(QString("%1 %2").arg(tagIndices.size()).arg(tagIndices.size() == 1 ? singularTitle : pluralTitle));
|
||||
widget->show();
|
||||
}
|
||||
};
|
||||
|
||||
connect(m_gemModel, &GemModel::dataChanged, this, update);
|
||||
update();
|
||||
}
|
||||
|
||||
QStringList CartOverlayWidget::ConvertFromModelIndices(const QVector<QModelIndex>& gems) const
|
||||
@@ -154,15 +192,15 @@ namespace O3DE::ProjectManager
|
||||
// Adjust the label text whenever the model gets updated.
|
||||
connect(gemModel, &GemModel::dataChanged, [=]
|
||||
{
|
||||
const QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeAdded();
|
||||
const QVector<QModelIndex> toBeRemoved = m_gemModel->GatherGemsToBeRemoved();
|
||||
const QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true);
|
||||
const QVector<QModelIndex> toBeRemoved = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true);
|
||||
|
||||
const int count = toBeAdded.size() + toBeRemoved.size();
|
||||
m_countLabel->setText(QString::number(count));
|
||||
|
||||
m_dropDownButton->setVisible(!toBeAdded.isEmpty() || !toBeRemoved.isEmpty());
|
||||
|
||||
// Automatically close the overlay window in case there are no gems to be enabled or disabled anymore.
|
||||
// Automatically close the overlay window in case there are no gems to be activated or deactivated anymore.
|
||||
if (m_cartOverlay && toBeAdded.isEmpty() && toBeRemoved.isEmpty())
|
||||
{
|
||||
m_cartOverlay->deleteLater();
|
||||
@@ -186,8 +224,8 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void CartButton::ShowOverlay()
|
||||
{
|
||||
const QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeAdded();
|
||||
const QVector<QModelIndex> toBeRemoved = m_gemModel->GatherGemsToBeRemoved();
|
||||
const QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true);
|
||||
const QVector<QModelIndex> toBeRemoved = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true);
|
||||
if (toBeAdded.isEmpty() && toBeRemoved.isEmpty())
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/function/function_fwd.h>
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzQtComponents/Components/SearchLineEdit.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
@@ -30,22 +32,16 @@ namespace O3DE::ProjectManager
|
||||
|
||||
public:
|
||||
CartOverlayWidget(GemModel* gemModel, QWidget* parent = nullptr);
|
||||
void Update();
|
||||
|
||||
private:
|
||||
QStringList ConvertFromModelIndices(const QVector<QModelIndex>& gems) const;
|
||||
|
||||
using GetTagIndicesCallback = AZStd::function<QVector<QModelIndex>()>;
|
||||
void CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices);
|
||||
|
||||
QVBoxLayout* m_layout = nullptr;
|
||||
GemModel* m_gemModel = nullptr;
|
||||
|
||||
QWidget* m_enabledWidget = nullptr;
|
||||
QLabel* m_enabledLabel = nullptr;
|
||||
TagContainerWidget* m_enabledTagContainer = nullptr;
|
||||
|
||||
QWidget* m_disabledWidget = nullptr;
|
||||
QLabel* m_disabledLabel = nullptr;
|
||||
TagContainerWidget* m_disabledTagContainer = nullptr;
|
||||
|
||||
inline constexpr static int s_width = 240;
|
||||
};
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@ namespace O3DE::ProjectManager
|
||||
m_gemModel->AddGem(gemInfo);
|
||||
}
|
||||
|
||||
m_gemModel->UpdateGemDependencies();
|
||||
|
||||
// Gather enabled gems for the given project.
|
||||
auto enabledGemNamesResult = PythonBindingsInterface::Get()->GetEnabledGemNames(projectPath);
|
||||
if (enabledGemNamesResult.IsSuccess())
|
||||
|
||||
@@ -226,13 +226,20 @@ namespace O3DE::ProjectManager
|
||||
QVector<int> elementCounts;
|
||||
const int totalGems = m_gemModel->rowCount();
|
||||
const int selectedGemTotal = m_gemModel->TotalAddedGems();
|
||||
const int enabledGemTotal = m_gemModel->TotalAddedGems(/*includeDependencies=*/true);
|
||||
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemStatusString(GemSortFilterProxyModel::GemStatus::Unselected));
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemSelectedString(GemSortFilterProxyModel::GemSelected::Unselected));
|
||||
elementCounts.push_back(totalGems - selectedGemTotal);
|
||||
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemStatusString(GemSortFilterProxyModel::GemStatus::Selected));
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemSelectedString(GemSortFilterProxyModel::GemSelected::Selected));
|
||||
elementCounts.push_back(selectedGemTotal);
|
||||
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Inactive));
|
||||
elementCounts.push_back(totalGems - enabledGemTotal);
|
||||
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Active));
|
||||
elementCounts.push_back(enabledGemTotal);
|
||||
|
||||
bool wasCollapsed = false;
|
||||
if (m_statusFilter)
|
||||
{
|
||||
@@ -253,48 +260,53 @@ namespace O3DE::ProjectManager
|
||||
m_statusFilter->deleteLater();
|
||||
m_statusFilter = filterWidget;
|
||||
|
||||
const GemSortFilterProxyModel::GemStatus currentFilterState = m_filterProxyModel->GetGemStatus();
|
||||
const QList<QAbstractButton*> buttons = m_statusFilter->GetButtonGroup()->buttons();
|
||||
for (int statusFilterIndex = 0; statusFilterIndex < buttons.size(); ++statusFilterIndex)
|
||||
|
||||
QAbstractButton* unselectedButton = buttons[0];
|
||||
QAbstractButton* selectedButton = buttons[1];
|
||||
unselectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Unselected);
|
||||
selectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Selected);
|
||||
|
||||
auto updateGemSelection = [=]([[maybe_unused]] bool checked)
|
||||
{
|
||||
const GemSortFilterProxyModel::GemStatus gemStatus = static_cast<GemSortFilterProxyModel::GemStatus>(statusFilterIndex);
|
||||
QAbstractButton* button = buttons[statusFilterIndex];
|
||||
|
||||
if (static_cast<GemSortFilterProxyModel::GemStatus>(statusFilterIndex) == currentFilterState)
|
||||
if (unselectedButton->isChecked() && !selectedButton->isChecked())
|
||||
{
|
||||
button->setChecked(true);
|
||||
m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Unselected);
|
||||
}
|
||||
else if (!unselectedButton->isChecked() && selectedButton->isChecked())
|
||||
{
|
||||
m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::NoFilter);
|
||||
}
|
||||
};
|
||||
connect(unselectedButton, &QAbstractButton::toggled, this, updateGemSelection);
|
||||
connect(selectedButton, &QAbstractButton::toggled, this, updateGemSelection);
|
||||
|
||||
connect(
|
||||
button, &QAbstractButton::toggled, this,
|
||||
[=](bool checked)
|
||||
{
|
||||
GemSortFilterProxyModel::GemStatus filterStatus = m_filterProxyModel->GetGemStatus();
|
||||
if (checked)
|
||||
{
|
||||
if (filterStatus == GemSortFilterProxyModel::GemStatus::NoFilter)
|
||||
{
|
||||
filterStatus = gemStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
filterStatus = GemSortFilterProxyModel::GemStatus::NoFilter;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filterStatus != gemStatus)
|
||||
{
|
||||
filterStatus = static_cast<GemSortFilterProxyModel::GemStatus>(!gemStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
filterStatus = GemSortFilterProxyModel::GemStatus::NoFilter;
|
||||
}
|
||||
}
|
||||
m_filterProxyModel->SetGemStatus(filterStatus);
|
||||
});
|
||||
}
|
||||
QAbstractButton* inactiveButton = buttons[2];
|
||||
QAbstractButton* activeButton = buttons[3];
|
||||
inactiveButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Inactive);
|
||||
activeButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Active);
|
||||
|
||||
auto updateGemActive = [=]([[maybe_unused]] bool checked)
|
||||
{
|
||||
if (inactiveButton->isChecked() && !activeButton->isChecked())
|
||||
{
|
||||
m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Inactive);
|
||||
}
|
||||
else if (!inactiveButton->isChecked() && activeButton->isChecked())
|
||||
{
|
||||
m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Active);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::NoFilter);
|
||||
}
|
||||
};
|
||||
connect(inactiveButton, &QAbstractButton::toggled, this, updateGemActive);
|
||||
connect(activeButton, &QAbstractButton::toggled, this, updateGemActive);
|
||||
}
|
||||
|
||||
void GemFilterWidget::AddGemOriginFilter()
|
||||
@@ -487,7 +499,7 @@ namespace O3DE::ProjectManager
|
||||
const QString& feature = elementNames[i];
|
||||
QAbstractButton* button = buttons[i];
|
||||
|
||||
// Adjust the proxy model and enable or disable the clicked feature used for filtering.
|
||||
// Adjust the proxy model and enable the clicked feature used for filtering.
|
||||
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
|
||||
{
|
||||
QSet<QString> features = m_filterProxyModel->GetFeatures();
|
||||
|
||||
@@ -75,8 +75,7 @@ namespace O3DE::ProjectManager
|
||||
QString m_version = "Unknown Version";
|
||||
QString m_lastUpdatedDate = "Unknown Date";
|
||||
int m_binarySizeInKB = 0;
|
||||
QStringList m_dependingGemUuids;
|
||||
QStringList m_conflictingGemUuids;
|
||||
QStringList m_dependencies;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <GemCatalog/GemInspector.h>
|
||||
#include <GemCatalog/GemItemDelegate.h>
|
||||
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QSpacerItem>
|
||||
@@ -83,14 +84,13 @@ namespace O3DE::ProjectManager
|
||||
m_reqirementsTextLabel->hide();
|
||||
}
|
||||
|
||||
// Depending and conflicting gems
|
||||
// Depending gems
|
||||
m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGemNames(modelIndex));
|
||||
m_conflictingGems->Update("Conflicting Gems", "The following Gems will be automatically disabled with this Gem.", m_model->GetConflictingGemNames(modelIndex));
|
||||
|
||||
// Additional information
|
||||
m_versionLabel->setText(QString("Gem Version: %1").arg(m_model->GetVersion(modelIndex)));
|
||||
m_lastUpdatedLabel->setText(QString("Last Updated: %1").arg(m_model->GetLastUpdated(modelIndex)));
|
||||
m_binarySizeLabel->setText(QString("Binary Size: %1 KB").arg(QString::number(m_model->GetBinarySizeInKB(modelIndex))));
|
||||
m_binarySizeLabel->setText(QString("Binary Size: %1 KB").arg(m_model->GetBinarySizeInKB(modelIndex)));
|
||||
|
||||
m_mainWidget->adjustSize();
|
||||
m_mainWidget->show();
|
||||
@@ -173,15 +173,11 @@ namespace O3DE::ProjectManager
|
||||
|
||||
m_mainLayout->addSpacing(20);
|
||||
|
||||
// Depending and conflicting gems
|
||||
// Depending gems
|
||||
m_dependingGems = new GemsSubWidget();
|
||||
m_mainLayout->addWidget(m_dependingGems);
|
||||
m_mainLayout->addSpacing(20);
|
||||
|
||||
m_conflictingGems = new GemsSubWidget();
|
||||
m_mainLayout->addWidget(m_conflictingGems);
|
||||
m_mainLayout->addSpacing(20);
|
||||
|
||||
// Additional information
|
||||
QLabel* additionalInfoLabel = CreateStyledLabel(m_mainLayout, 14, s_headerColor);
|
||||
additionalInfoLabel->setText("Additional Information");
|
||||
@@ -190,27 +186,4 @@ namespace O3DE::ProjectManager
|
||||
m_lastUpdatedLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor);
|
||||
m_binarySizeLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor);
|
||||
}
|
||||
|
||||
GemInspector::GemsSubWidget::GemsSubWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_layout = new QVBoxLayout();
|
||||
m_layout->setAlignment(Qt::AlignTop);
|
||||
m_layout->setMargin(0);
|
||||
setLayout(m_layout);
|
||||
|
||||
m_titleLabel = GemInspector::CreateStyledLabel(m_layout, 16, s_headerColor);
|
||||
m_textLabel = GemInspector::CreateStyledLabel(m_layout, 10, s_textColor);
|
||||
m_textLabel->setWordWrap(true);
|
||||
|
||||
m_tagWidget = new TagContainerWidget();
|
||||
m_layout->addWidget(m_tagWidget);
|
||||
}
|
||||
|
||||
void GemInspector::GemsSubWidget::Update(const QString& title, const QString& text, const QStringList& gemNames)
|
||||
{
|
||||
m_titleLabel->setText(title);
|
||||
m_textLabel->setText(text);
|
||||
m_tagWidget->Update(gemNames);
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <LinkWidget.h>
|
||||
#include <TagWidget.h>
|
||||
#include <GemCatalog/GemInfo.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <GemsSubWidget.h>
|
||||
#include <LinkWidget.h>
|
||||
|
||||
#include <QItemSelection>
|
||||
#include <QScrollArea>
|
||||
#include <QWidget>
|
||||
@@ -43,21 +44,6 @@ namespace O3DE::ProjectManager
|
||||
void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
|
||||
private:
|
||||
// Title, description and tag widget container used for the depending and conflicting gems
|
||||
class GemsSubWidget
|
||||
: public QWidget
|
||||
{
|
||||
public:
|
||||
GemsSubWidget(QWidget* parent = nullptr);
|
||||
void Update(const QString& title, const QString& text, const QStringList& gemNames);
|
||||
|
||||
private:
|
||||
QLabel* m_titleLabel = nullptr;
|
||||
QLabel* m_textLabel = nullptr;
|
||||
QVBoxLayout* m_layout = nullptr;
|
||||
TagContainerWidget* m_tagWidget = nullptr;
|
||||
};
|
||||
|
||||
void InitMainWidget();
|
||||
|
||||
GemModel* m_model = nullptr;
|
||||
@@ -78,7 +64,6 @@ namespace O3DE::ProjectManager
|
||||
|
||||
// Depending and conflicting gems
|
||||
GemsSubWidget* m_dependingGems = nullptr;
|
||||
GemsSubWidget* m_conflictingGems = nullptr;
|
||||
|
||||
// Additional information
|
||||
QLabel* m_versionLabel = nullptr;
|
||||
|
||||
@@ -8,9 +8,14 @@
|
||||
|
||||
#include <GemCatalog/GemItemDelegate.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <QEvent>
|
||||
#include <QAbstractItemView>
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
#include <QHelpEvent>
|
||||
#include <QToolTip>
|
||||
#include <QHoverEvent>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -149,8 +154,7 @@ namespace O3DE::ProjectManager
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::MouseButtonPress)
|
||||
else if (event->type() == QEvent::MouseButtonPress )
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
|
||||
@@ -169,6 +173,69 @@ namespace O3DE::ProjectManager
|
||||
return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
|
||||
}
|
||||
|
||||
QString GetGemNameList(const QVector<QModelIndex> modelIndices)
|
||||
{
|
||||
QString gemNameList;
|
||||
for (int i = 0; i < modelIndices.size(); ++i)
|
||||
{
|
||||
if (!gemNameList.isEmpty())
|
||||
{
|
||||
if (i == modelIndices.size() - 1)
|
||||
{
|
||||
gemNameList.append(" and ");
|
||||
}
|
||||
else
|
||||
{
|
||||
gemNameList.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
gemNameList.append(GemModel::GetDisplayName(modelIndices[i]));
|
||||
}
|
||||
|
||||
return gemNameList;
|
||||
}
|
||||
|
||||
bool GemItemDelegate::helpEvent(QHelpEvent* event, QAbstractItemView* view, const QStyleOptionViewItem& option, const QModelIndex& index)
|
||||
{
|
||||
if (event->type() == QEvent::ToolTip)
|
||||
{
|
||||
QRect fullRect, itemRect, contentRect;
|
||||
CalcRects(option, fullRect, itemRect, contentRect);
|
||||
const QRect buttonRect = CalcButtonRect(contentRect);
|
||||
if (buttonRect.contains(event->pos()))
|
||||
{
|
||||
if (!QToolTip::isVisible())
|
||||
{
|
||||
if(GemModel::IsAddedDependency(index) && !GemModel::IsAdded(index))
|
||||
{
|
||||
const GemModel* gemModel = GemModel::GetSourceModel(index.model());
|
||||
AZ_Assert(gemModel, "Failed to obtain GemModel");
|
||||
|
||||
// we only want to display the gems that must be de-selected to automatically
|
||||
// disable this dependency, so don't include any that haven't been selected (added)
|
||||
constexpr bool addedOnly = true;
|
||||
QVector<QModelIndex> dependents = gemModel->GatherDependentGems(index, addedOnly);
|
||||
QString nameList = GetGemNameList(dependents);
|
||||
if (!nameList.isEmpty())
|
||||
{
|
||||
QToolTip::showText(event->globalPos(), tr("This gem is a dependency of %1.\nTo disable this gem, first disable %1.").arg(nameList));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (QToolTip::isVisible())
|
||||
{
|
||||
QToolTip::hideText();
|
||||
event->ignore();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::helpEvent(event, view, option, index);
|
||||
}
|
||||
|
||||
void GemItemDelegate::CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const
|
||||
{
|
||||
outFullRect = QRect(option.rect);
|
||||
@@ -260,14 +327,20 @@ namespace O3DE::ProjectManager
|
||||
const QRect buttonRect = CalcButtonRect(contentRect);
|
||||
QPoint circleCenter;
|
||||
|
||||
const bool isAdded = GemModel::IsAdded(modelIndex);
|
||||
if (isAdded)
|
||||
if (GemModel::IsAdded(modelIndex))
|
||||
{
|
||||
painter->setBrush(m_buttonEnabledColor);
|
||||
painter->setPen(m_buttonEnabledColor);
|
||||
|
||||
circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1);
|
||||
}
|
||||
else if (GemModel::IsAddedDependency(modelIndex))
|
||||
{
|
||||
painter->setBrush(m_buttonImplicitlyEnabledColor);
|
||||
painter->setPen(m_buttonImplicitlyEnabledColor);
|
||||
|
||||
circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius, 1);
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace O3DE::ProjectManager
|
||||
~GemItemDelegate() = default;
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
|
||||
bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
|
||||
|
||||
// Colors
|
||||
@@ -39,6 +38,7 @@ namespace O3DE::ProjectManager
|
||||
const QColor m_itemBackgroundColor = QColor("#404040"); // Background color of the gem item
|
||||
const QColor m_borderColor = QColor("#1E70EB");
|
||||
const QColor m_buttonEnabledColor = QColor("#00B931");
|
||||
const QColor m_buttonImplicitlyEnabledColor = QColor("#BCBCBE");
|
||||
|
||||
// Item
|
||||
inline constexpr static int s_height = 105; // Gem item total height
|
||||
@@ -65,6 +65,9 @@ namespace O3DE::ProjectManager
|
||||
inline constexpr static int s_featureTagSpacing = 7;
|
||||
|
||||
protected:
|
||||
bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override;
|
||||
bool helpEvent(QHelpEvent* event, QAbstractItemView* view, const QStyleOptionViewItem& option, const QModelIndex& index) override;
|
||||
|
||||
void CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const;
|
||||
QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const;
|
||||
QRect CalcButtonRect(const QRect& contentRect) const;
|
||||
|
||||
@@ -60,11 +60,14 @@ namespace O3DE::ProjectManager
|
||||
QLabel* showCountLabel = new QLabel();
|
||||
showCountLabel->setObjectName("GemCatalogHeaderShowCountLabel");
|
||||
topLayout->addWidget(showCountLabel);
|
||||
connect(proxyModel, &GemSortFilterProxyModel::OnInvalidated, this, [=]
|
||||
{
|
||||
|
||||
auto refreshGemCountUI = [=]() {
|
||||
const int numGemsShown = proxyModel->rowCount();
|
||||
showCountLabel->setText(QString(tr("showing %1 Gems")).arg(numGemsShown));
|
||||
});
|
||||
};
|
||||
|
||||
connect(proxyModel, &GemSortFilterProxyModel::OnInvalidated, this, refreshGemCountUI);
|
||||
connect(proxyModel->GetSourceModel(), &GemModel::dataChanged, this, refreshGemCountUI);
|
||||
|
||||
topLayout->addSpacing(GemItemDelegate::s_contentMargins.right() + GemItemDelegate::s_borderWidth);
|
||||
|
||||
|
||||
@@ -9,9 +9,26 @@
|
||||
#include <GemCatalog/GemListView.h>
|
||||
#include <GemCatalog/GemItemDelegate.h>
|
||||
#include <QStandardItemModel>
|
||||
#include <QProxyStyle>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemListViewProxyStyle : public QProxyStyle
|
||||
{
|
||||
public:
|
||||
using QProxyStyle::QProxyStyle;
|
||||
int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override
|
||||
{
|
||||
if (hint == QStyle::SH_ToolTip_WakeUpDelay || hint == QStyle::SH_ToolTip_FallAsleepDelay)
|
||||
{
|
||||
// no delay
|
||||
return 0;
|
||||
}
|
||||
|
||||
return QProxyStyle::styleHint(hint, option, widget, returnData);
|
||||
}
|
||||
};
|
||||
|
||||
GemListView::GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent)
|
||||
: QListView(parent)
|
||||
{
|
||||
@@ -21,5 +38,8 @@ namespace O3DE::ProjectManager
|
||||
setModel(model);
|
||||
setSelectionModel(selectionModel);
|
||||
setItemDelegate(new GemItemDelegate(model, this));
|
||||
|
||||
// use a custom proxy style so we get immediate tooltips for gem radio buttons
|
||||
setStyle(new GemListViewProxyStyle(this->style()));
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
@@ -40,8 +41,7 @@ namespace O3DE::ProjectManager
|
||||
item->setData(gemInfo.m_isAdded, RoleIsAdded);
|
||||
item->setData(gemInfo.m_directoryLink, RoleDirectoryLink);
|
||||
item->setData(gemInfo.m_documentationLink, RoleDocLink);
|
||||
item->setData(gemInfo.m_dependingGemUuids, RoleDependingGems);
|
||||
item->setData(gemInfo.m_conflictingGemUuids, RoleConflictingGems);
|
||||
item->setData(gemInfo.m_dependencies, RoleDependingGems);
|
||||
item->setData(gemInfo.m_version, RoleVersion);
|
||||
item->setData(gemInfo.m_lastUpdatedDate, RoleLastUpdated);
|
||||
item->setData(gemInfo.m_binarySizeInKB, RoleBinarySize);
|
||||
@@ -60,6 +60,39 @@ namespace O3DE::ProjectManager
|
||||
clear();
|
||||
}
|
||||
|
||||
void GemModel::UpdateGemDependencies()
|
||||
{
|
||||
m_gemDependencyMap.clear();
|
||||
m_gemReverseDependencyMap.clear();
|
||||
|
||||
for (auto iter = m_nameToIndexMap.begin(); iter != m_nameToIndexMap.end(); ++iter)
|
||||
{
|
||||
const QString& key = iter.key();
|
||||
const QModelIndex modelIndex = iter.value();
|
||||
QSet<QModelIndex> dependencies;
|
||||
GetAllDependingGems(modelIndex, dependencies);
|
||||
if (!dependencies.isEmpty())
|
||||
{
|
||||
m_gemDependencyMap.insert(key, dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto iter = m_gemDependencyMap.begin(); iter != m_gemDependencyMap.end(); ++iter)
|
||||
{
|
||||
const QString& dependant = iter.key();
|
||||
for (const QModelIndex& dependency : iter.value())
|
||||
{
|
||||
const QString& dependencyName = dependency.data(RoleName).toString();
|
||||
if (!m_gemReverseDependencyMap.contains(dependencyName))
|
||||
{
|
||||
m_gemReverseDependencyMap.insert(dependencyName, QSet<QModelIndex>());
|
||||
}
|
||||
|
||||
m_gemReverseDependencyMap[dependencyName].insert(m_nameToIndexMap[dependant]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString GemModel::GetName(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleName).toString();
|
||||
@@ -125,49 +158,46 @@ namespace O3DE::ProjectManager
|
||||
return {};
|
||||
}
|
||||
|
||||
void GemModel::FindGemNamesByNameStrings(QStringList& inOutGemNames)
|
||||
void GemModel::FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames)
|
||||
{
|
||||
for (QString& dependingGemString : inOutGemNames)
|
||||
for (QString& name : inOutGemNames)
|
||||
{
|
||||
QModelIndex modelIndex = FindIndexByNameString(dependingGemString);
|
||||
QModelIndex modelIndex = FindIndexByNameString(name);
|
||||
if (modelIndex.isValid())
|
||||
{
|
||||
dependingGemString = GetDisplayName(modelIndex);
|
||||
name = GetDisplayName(modelIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList GemModel::GetDependingGemUuids(const QModelIndex& modelIndex)
|
||||
QStringList GemModel::GetDependingGems(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleDependingGems).toStringList();
|
||||
}
|
||||
|
||||
void GemModel::GetAllDependingGems(const QModelIndex& modelIndex, QSet<QModelIndex>& inOutGems)
|
||||
{
|
||||
QStringList dependencies = GetDependingGems(modelIndex);
|
||||
for (const QString& dependency : dependencies)
|
||||
{
|
||||
QModelIndex dependencyIndex = FindIndexByNameString(dependency);
|
||||
if (!inOutGems.contains(dependencyIndex))
|
||||
{
|
||||
inOutGems.insert(dependencyIndex);
|
||||
GetAllDependingGems(dependencyIndex, inOutGems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList GemModel::GetDependingGemNames(const QModelIndex& modelIndex)
|
||||
{
|
||||
QStringList result = GetDependingGemUuids(modelIndex);
|
||||
QStringList result = GetDependingGems(modelIndex);
|
||||
if (result.isEmpty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
FindGemNamesByNameStrings(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList GemModel::GetConflictingGemUuids(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleConflictingGems).toStringList();
|
||||
}
|
||||
|
||||
QStringList GemModel::GetConflictingGemNames(const QModelIndex& modelIndex)
|
||||
{
|
||||
QStringList result = GetConflictingGemUuids(modelIndex);
|
||||
if (result.isEmpty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
FindGemNamesByNameStrings(result);
|
||||
FindGemDisplayNamesByNameStrings(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -201,29 +231,146 @@ namespace O3DE::ProjectManager
|
||||
return modelIndex.data(RoleRequirement).toString();
|
||||
}
|
||||
|
||||
GemModel* GemModel::GetSourceModel(QAbstractItemModel* model)
|
||||
{
|
||||
GemSortFilterProxyModel* proxyModel = qobject_cast<GemSortFilterProxyModel*>(model);
|
||||
if (proxyModel)
|
||||
{
|
||||
return proxyModel->GetSourceModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
return qobject_cast<GemModel*>(model);
|
||||
}
|
||||
}
|
||||
|
||||
const GemModel* GemModel::GetSourceModel(const QAbstractItemModel* model)
|
||||
{
|
||||
const GemSortFilterProxyModel* proxyModel = qobject_cast<const GemSortFilterProxyModel*>(model);
|
||||
if (proxyModel)
|
||||
{
|
||||
return proxyModel->GetSourceModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
return qobject_cast<const GemModel*>(model);
|
||||
}
|
||||
}
|
||||
|
||||
bool GemModel::IsAdded(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleIsAdded).toBool();
|
||||
}
|
||||
|
||||
bool GemModel::IsAddedDependency(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleIsAddedDependency).toBool();
|
||||
}
|
||||
|
||||
void GemModel::SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded)
|
||||
{
|
||||
model.setData(modelIndex, isAdded, RoleIsAdded);
|
||||
|
||||
UpdateDependencies(model, modelIndex);
|
||||
}
|
||||
|
||||
bool GemModel::HasDependentGems(const QModelIndex& modelIndex) const
|
||||
{
|
||||
QVector<QModelIndex> dependentGems = GatherDependentGems(modelIndex);
|
||||
for (const QModelIndex& dependency : dependentGems)
|
||||
{
|
||||
if (IsAdded(dependency))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GemModel::UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex)
|
||||
{
|
||||
GemModel* gemModel = GetSourceModel(&model);
|
||||
AZ_Assert(gemModel, "Failed to obtain GemModel");
|
||||
|
||||
QVector<QModelIndex> dependencies = gemModel->GatherGemDependencies(modelIndex);
|
||||
if (IsAdded(modelIndex))
|
||||
{
|
||||
for (const QModelIndex& dependency : dependencies)
|
||||
{
|
||||
SetIsAddedDependency(*gemModel, dependency, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// still a dependency if some added gem depends on this one
|
||||
SetIsAddedDependency(model, modelIndex, gemModel->HasDependentGems(modelIndex));
|
||||
|
||||
for (const QModelIndex& dependency : dependencies)
|
||||
{
|
||||
SetIsAddedDependency(*gemModel, dependency, gemModel->HasDependentGems(dependency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GemModel::SetIsAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded)
|
||||
{
|
||||
model.setData(modelIndex, isAdded, RoleIsAddedDependency);
|
||||
}
|
||||
|
||||
void GemModel::SetWasPreviouslyAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded)
|
||||
{
|
||||
model.setData(modelIndex, wasAdded, RoleWasPreviouslyAdded);
|
||||
|
||||
if (wasAdded)
|
||||
{
|
||||
// update all dependencies
|
||||
GemModel* gemModel = GetSourceModel(&model);
|
||||
AZ_Assert(gemModel, "Failed to obtain GemModel");
|
||||
QVector<QModelIndex> dependencies = gemModel->GatherGemDependencies(modelIndex);
|
||||
for (const QModelIndex& dependency : dependencies)
|
||||
{
|
||||
SetWasPreviouslyAddedDependency(*gemModel, dependency, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GemModel::NeedsToBeAdded(const QModelIndex& modelIndex)
|
||||
void GemModel::SetWasPreviouslyAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded)
|
||||
{
|
||||
return (!modelIndex.data(RoleWasPreviouslyAdded).toBool() && modelIndex.data(RoleIsAdded).toBool());
|
||||
model.setData(modelIndex, wasAdded, RoleWasPreviouslyAddedDependency);
|
||||
}
|
||||
|
||||
bool GemModel::NeedsToBeRemoved(const QModelIndex& modelIndex)
|
||||
bool GemModel::WasPreviouslyAdded(const QModelIndex& modelIndex)
|
||||
{
|
||||
return (modelIndex.data(RoleWasPreviouslyAdded).toBool() && !modelIndex.data(RoleIsAdded).toBool());
|
||||
return modelIndex.data(RoleWasPreviouslyAdded).toBool();
|
||||
}
|
||||
|
||||
bool GemModel::WasPreviouslyAddedDependency(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleWasPreviouslyAddedDependency).toBool();
|
||||
}
|
||||
|
||||
bool GemModel::NeedsToBeAdded(const QModelIndex& modelIndex, bool includeDependencies)
|
||||
{
|
||||
bool previouslyAdded = modelIndex.data(RoleWasPreviouslyAdded).toBool();
|
||||
bool added = modelIndex.data(RoleIsAdded).toBool();
|
||||
if (includeDependencies)
|
||||
{
|
||||
previouslyAdded |= modelIndex.data(RoleWasPreviouslyAddedDependency).toBool();
|
||||
added |= modelIndex.data(RoleIsAddedDependency).toBool();
|
||||
}
|
||||
return !previouslyAdded && added;
|
||||
}
|
||||
|
||||
bool GemModel::NeedsToBeRemoved(const QModelIndex& modelIndex, bool includeDependencies)
|
||||
{
|
||||
bool previouslyAdded = modelIndex.data(RoleWasPreviouslyAdded).toBool();
|
||||
bool added = modelIndex.data(RoleIsAdded).toBool();
|
||||
if (includeDependencies)
|
||||
{
|
||||
previouslyAdded |= modelIndex.data(RoleWasPreviouslyAddedDependency).toBool();
|
||||
added |= modelIndex.data(RoleIsAddedDependency).toBool();
|
||||
}
|
||||
return previouslyAdded && !added;
|
||||
}
|
||||
|
||||
bool GemModel::HasRequirement(const QModelIndex& modelIndex)
|
||||
@@ -244,13 +391,44 @@ namespace O3DE::ProjectManager
|
||||
return false;
|
||||
}
|
||||
|
||||
QVector<QModelIndex> GemModel::GatherGemsToBeAdded() const
|
||||
QVector<QModelIndex> GemModel::GatherGemDependencies(const QModelIndex& modelIndex) const
|
||||
{
|
||||
QVector<QModelIndex> result;
|
||||
const QString& gemName = modelIndex.data(RoleName).toString();
|
||||
if (m_gemDependencyMap.contains(gemName))
|
||||
{
|
||||
for (const QModelIndex& dependency : m_gemDependencyMap[gemName])
|
||||
{
|
||||
result.push_back(dependency);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<QModelIndex> GemModel::GatherDependentGems(const QModelIndex& modelIndex, bool addedOnly) const
|
||||
{
|
||||
QVector<QModelIndex> result;
|
||||
const QString& gemName = modelIndex.data(RoleName).toString();
|
||||
if (m_gemReverseDependencyMap.contains(gemName))
|
||||
{
|
||||
for (const QModelIndex& dependency : m_gemReverseDependencyMap[gemName])
|
||||
{
|
||||
if (!addedOnly || GemModel::IsAdded(dependency))
|
||||
{
|
||||
result.push_back(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<QModelIndex> GemModel::GatherGemsToBeAdded(bool includeDependencies) const
|
||||
{
|
||||
QVector<QModelIndex> result;
|
||||
for (int row = 0; row < rowCount(); ++row)
|
||||
{
|
||||
const QModelIndex modelIndex = index(row, 0);
|
||||
if (NeedsToBeAdded(modelIndex))
|
||||
if (NeedsToBeAdded(modelIndex, includeDependencies))
|
||||
{
|
||||
result.push_back(modelIndex);
|
||||
}
|
||||
@@ -258,13 +436,13 @@ namespace O3DE::ProjectManager
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<QModelIndex> GemModel::GatherGemsToBeRemoved() const
|
||||
QVector<QModelIndex> GemModel::GatherGemsToBeRemoved(bool includeDependencies) const
|
||||
{
|
||||
QVector<QModelIndex> result;
|
||||
for (int row = 0; row < rowCount(); ++row)
|
||||
{
|
||||
const QModelIndex modelIndex = index(row, 0);
|
||||
if (NeedsToBeRemoved(modelIndex))
|
||||
if (NeedsToBeRemoved(modelIndex, includeDependencies))
|
||||
{
|
||||
result.push_back(modelIndex);
|
||||
}
|
||||
@@ -272,13 +450,13 @@ namespace O3DE::ProjectManager
|
||||
return result;
|
||||
}
|
||||
|
||||
int GemModel::TotalAddedGems() const
|
||||
int GemModel::TotalAddedGems(bool includeDependencies) const
|
||||
{
|
||||
int result = 0;
|
||||
for (int row = 0; row < rowCount(); ++row)
|
||||
{
|
||||
const QModelIndex modelIndex = index(row, 0);
|
||||
if (IsAdded(modelIndex))
|
||||
if (IsAdded(modelIndex) || (includeDependencies && IsAddedDependency(modelIndex)))
|
||||
{
|
||||
++result;
|
||||
}
|
||||
|
||||
@@ -28,13 +28,11 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void AddGem(const GemInfo& gemInfo);
|
||||
void Clear();
|
||||
void UpdateGemDependencies();
|
||||
|
||||
QModelIndex FindIndexByNameString(const QString& nameString) const;
|
||||
void FindGemNamesByNameStrings(QStringList& inOutGemNames);
|
||||
QStringList GetDependingGemUuids(const QModelIndex& modelIndex);
|
||||
QStringList GetDependingGemNames(const QModelIndex& modelIndex);
|
||||
QStringList GetConflictingGemUuids(const QModelIndex& modelIndex);
|
||||
QStringList GetConflictingGemNames(const QModelIndex& modelIndex);
|
||||
bool HasDependentGems(const QModelIndex& modelIndex) const;
|
||||
|
||||
static QString GetName(const QModelIndex& modelIndex);
|
||||
static QString GetDisplayName(const QModelIndex& modelIndex);
|
||||
@@ -51,22 +49,36 @@ namespace O3DE::ProjectManager
|
||||
static QStringList GetFeatures(const QModelIndex& modelIndex);
|
||||
static QString GetPath(const QModelIndex& modelIndex);
|
||||
static QString GetRequirement(const QModelIndex& modelIndex);
|
||||
static GemModel* GetSourceModel(QAbstractItemModel* model);
|
||||
static const GemModel* GetSourceModel(const QAbstractItemModel* model);
|
||||
|
||||
static bool IsAdded(const QModelIndex& modelIndex);
|
||||
static bool IsAddedDependency(const QModelIndex& modelIndex);
|
||||
static void SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded);
|
||||
static void SetIsAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded);
|
||||
static void SetWasPreviouslyAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded);
|
||||
static bool NeedsToBeAdded(const QModelIndex& modelIndex);
|
||||
static bool NeedsToBeRemoved(const QModelIndex& modelIndex);
|
||||
static bool WasPreviouslyAdded(const QModelIndex& modelIndex);
|
||||
static void SetWasPreviouslyAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded);
|
||||
static bool WasPreviouslyAddedDependency(const QModelIndex& modelIndex);
|
||||
static bool NeedsToBeAdded(const QModelIndex& modelIndex, bool includeDependencies = false);
|
||||
static bool NeedsToBeRemoved(const QModelIndex& modelIndex, bool includeDependencies = false);
|
||||
static bool HasRequirement(const QModelIndex& modelIndex);
|
||||
static void UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex);
|
||||
|
||||
bool DoGemsToBeAddedHaveRequirements() const;
|
||||
|
||||
QVector<QModelIndex> GatherGemsToBeAdded() const;
|
||||
QVector<QModelIndex> GatherGemsToBeRemoved() const;
|
||||
QVector<QModelIndex> GatherGemDependencies(const QModelIndex& modelIndex) const;
|
||||
QVector<QModelIndex> GatherDependentGems(const QModelIndex& modelIndex, bool addedOnly = false) const;
|
||||
QVector<QModelIndex> GatherGemsToBeAdded(bool includeDependencies = false) const;
|
||||
QVector<QModelIndex> GatherGemsToBeRemoved(bool includeDependencies = false) const;
|
||||
|
||||
int TotalAddedGems() const;
|
||||
int TotalAddedGems(bool includeDependencies = false) const;
|
||||
|
||||
private:
|
||||
void FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames);
|
||||
void GetAllDependingGems(const QModelIndex& modelIndex, QSet<QModelIndex>& inOutGems);
|
||||
QStringList GetDependingGems(const QModelIndex& modelIndex);
|
||||
|
||||
enum UserRole
|
||||
{
|
||||
RoleName = Qt::UserRole,
|
||||
@@ -76,11 +88,12 @@ namespace O3DE::ProjectManager
|
||||
RolePlatforms,
|
||||
RoleSummary,
|
||||
RoleWasPreviouslyAdded,
|
||||
RoleWasPreviouslyAddedDependency,
|
||||
RoleIsAdded,
|
||||
RoleIsAddedDependency,
|
||||
RoleDirectoryLink,
|
||||
RoleDocLink,
|
||||
RoleDependingGems,
|
||||
RoleConflictingGems,
|
||||
RoleVersion,
|
||||
RoleLastUpdated,
|
||||
RoleBinarySize,
|
||||
@@ -92,5 +105,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
QHash<QString, QModelIndex> m_nameToIndexMap;
|
||||
QItemSelectionModel* m_selectionModel = nullptr;
|
||||
QHash<QString, QSet<QModelIndex>> m_gemDependencyMap;
|
||||
QHash<QString, QSet<QModelIndex>> m_gemReverseDependencyMap;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -50,11 +50,21 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
// Gem status
|
||||
if (m_gemStatusFilter != GemStatus::NoFilter)
|
||||
// Gem selected
|
||||
if (m_gemSelectedFilter != GemSelected::NoFilter)
|
||||
{
|
||||
const GemStatus sourceGemStatus = static_cast<GemStatus>(GemModel::IsAdded(sourceIndex));
|
||||
if (m_gemStatusFilter != sourceGemStatus)
|
||||
const GemSelected sourceGemStatus = static_cast<GemSelected>(GemModel::IsAdded(sourceIndex));
|
||||
if (m_gemSelectedFilter != sourceGemStatus)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Gem enabled
|
||||
if (m_gemActiveFilter != GemActive::NoFilter)
|
||||
{
|
||||
const GemActive sourceGemStatus = static_cast<GemActive>(GemModel::IsAdded(sourceIndex) || GemModel::IsAddedDependency(sourceIndex));
|
||||
if (m_gemActiveFilter != sourceGemStatus)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -148,19 +158,31 @@ namespace O3DE::ProjectManager
|
||||
return true;
|
||||
}
|
||||
|
||||
QString GemSortFilterProxyModel::GetGemStatusString(GemStatus status)
|
||||
QString GemSortFilterProxyModel::GetGemSelectedString(GemSelected status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case Unselected:
|
||||
case GemSelected::Unselected:
|
||||
return "Unselected";
|
||||
case Selected:
|
||||
case GemSelected::Selected:
|
||||
return "Selected";
|
||||
default:
|
||||
return "<Unknown Gem Status>";
|
||||
return "<Unknown Selection Status>";
|
||||
}
|
||||
}
|
||||
|
||||
QString GemSortFilterProxyModel::GetGemActiveString(GemActive status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case GemActive::Inactive:
|
||||
return "Inactive";
|
||||
case GemActive::Active:
|
||||
return "Active";
|
||||
default:
|
||||
return "<Unknown Active Status>";
|
||||
}
|
||||
}
|
||||
void GemSortFilterProxyModel::InvalidateFilter()
|
||||
{
|
||||
invalidate();
|
||||
|
||||
@@ -25,16 +25,23 @@ namespace O3DE::ProjectManager
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
enum GemStatus
|
||||
enum class GemSelected
|
||||
{
|
||||
NoFilter = -1,
|
||||
Unselected,
|
||||
Selected
|
||||
};
|
||||
enum class GemActive
|
||||
{
|
||||
NoFilter = -1,
|
||||
Inactive,
|
||||
Active
|
||||
};
|
||||
|
||||
GemSortFilterProxyModel(GemModel* sourceModel, QObject* parent = nullptr);
|
||||
|
||||
static QString GetGemStatusString(GemStatus status);
|
||||
static QString GetGemSelectedString(GemSelected status);
|
||||
static QString GetGemActiveString(GemActive status);
|
||||
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
|
||||
|
||||
@@ -43,8 +50,11 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void SetSearchString(const QString& searchString) { m_searchString = searchString; InvalidateFilter(); }
|
||||
|
||||
GemStatus GetGemStatus() const { return m_gemStatusFilter; }
|
||||
void SetGemStatus(GemStatus gemStatus) { m_gemStatusFilter = gemStatus; InvalidateFilter(); }
|
||||
GemSelected GetGemSelected() const { return m_gemSelectedFilter; }
|
||||
void SetGemSelected(GemSelected selected) { m_gemSelectedFilter = selected; InvalidateFilter(); }
|
||||
|
||||
GemActive GetGemActive() const { return m_gemActiveFilter; }
|
||||
void SetGemActive(GemActive enabled) { m_gemActiveFilter = enabled; InvalidateFilter(); }
|
||||
|
||||
GemInfo::GemOrigins GetGemOrigins() const { return m_gemOriginFilter; }
|
||||
void SetGemOrigins(const GemInfo::GemOrigins& gemOrigins) { m_gemOriginFilter = gemOrigins; InvalidateFilter(); }
|
||||
@@ -69,7 +79,8 @@ namespace O3DE::ProjectManager
|
||||
AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr;
|
||||
|
||||
QString m_searchString;
|
||||
GemStatus m_gemStatusFilter = GemStatus::NoFilter;
|
||||
GemSelected m_gemSelectedFilter = GemSelected::NoFilter;
|
||||
GemActive m_gemActiveFilter = GemActive::NoFilter;
|
||||
GemInfo::GemOrigins m_gemOriginFilter = {};
|
||||
GemInfo::Platforms m_platformFilter = {};
|
||||
GemInfo::Types m_typeFilter = {};
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemRepoInfo::GemRepoInfo(
|
||||
const QString& name, const QString& creator, const QString& summary, const QDateTime& lastUpdated, bool isEnabled = true)
|
||||
const QString& name,
|
||||
const QString& creator,
|
||||
const QDateTime& lastUpdated,
|
||||
bool isEnabled = true)
|
||||
: m_name(name)
|
||||
, m_creator(creator)
|
||||
, m_summary(summary)
|
||||
, m_lastUpdated(lastUpdated)
|
||||
, m_isEnabled(isEnabled)
|
||||
{
|
||||
|
||||
@@ -19,19 +19,25 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
public:
|
||||
GemRepoInfo() = default;
|
||||
GemRepoInfo(const QString& name, const QString& creator, const QString& summary, const QDateTime& lastUpdated, bool isEnabled);
|
||||
GemRepoInfo(
|
||||
const QString& name,
|
||||
const QString& creator,
|
||||
const QDateTime& lastUpdated,
|
||||
bool isEnabled);
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
bool operator<(const GemRepoInfo& gemRepoInfo) const;
|
||||
|
||||
QString m_path;
|
||||
QString m_path = "";
|
||||
QString m_name = "Unknown Gem Repo Name";
|
||||
QString m_creator = "Unknown Creator";
|
||||
bool m_isEnabled = false; //! Is the repo currently enabled for this engine?
|
||||
QString m_summary = "No summary provided.";
|
||||
QString m_directoryLink;
|
||||
QString m_repoLink;
|
||||
QString m_additionalInfo = "";
|
||||
QString m_directoryLink = "";
|
||||
QString m_repoLink = "";
|
||||
QStringList m_includedGemPaths = {};
|
||||
QDateTime m_lastUpdated;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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 <GemRepo/GemRepoInspector.h>
|
||||
#include <GemRepo/GemRepoItemDelegate.h>
|
||||
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QIcon>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemRepoInspector::GemRepoInspector(GemRepoModel* model, QWidget* parent)
|
||||
: QScrollArea(parent)
|
||||
, m_model(model)
|
||||
{
|
||||
setObjectName("gemRepoInspector");
|
||||
setWidgetResizable(true);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
|
||||
m_mainWidget = new QWidget();
|
||||
setWidget(m_mainWidget);
|
||||
|
||||
m_mainLayout = new QVBoxLayout();
|
||||
m_mainLayout->setMargin(15);
|
||||
m_mainLayout->setAlignment(Qt::AlignTop);
|
||||
m_mainWidget->setLayout(m_mainLayout);
|
||||
|
||||
InitMainWidget();
|
||||
|
||||
connect(m_model->GetSelectionModel(), &QItemSelectionModel::selectionChanged, this, &GemRepoInspector::OnSelectionChanged);
|
||||
Update({});
|
||||
}
|
||||
|
||||
void GemRepoInspector::OnSelectionChanged(const QItemSelection& selected, [[maybe_unused]] const QItemSelection& deselected)
|
||||
{
|
||||
const QModelIndexList selectedIndices = selected.indexes();
|
||||
if (selectedIndices.empty())
|
||||
{
|
||||
Update({});
|
||||
return;
|
||||
}
|
||||
|
||||
Update(selectedIndices[0]);
|
||||
}
|
||||
|
||||
void GemRepoInspector::Update(const QModelIndex& modelIndex)
|
||||
{
|
||||
if (!modelIndex.isValid())
|
||||
{
|
||||
m_mainWidget->hide();
|
||||
}
|
||||
|
||||
// Repo name and url link
|
||||
m_nameLabel->setText(m_model->GetName(modelIndex));
|
||||
m_repoLinkLabel->setText(m_model->GetRepoLink(modelIndex));
|
||||
m_repoLinkLabel->SetUrl(m_model->GetRepoLink(modelIndex));
|
||||
|
||||
// Repo summary
|
||||
m_summaryLabel->setText(m_model->GetSummary(modelIndex));
|
||||
m_summaryLabel->adjustSize();
|
||||
|
||||
// Additional information
|
||||
if (m_model->HasAdditionalInfo(modelIndex))
|
||||
{
|
||||
m_addInfoTitleLabel->show();
|
||||
m_addInfoTextLabel->show();
|
||||
|
||||
m_addInfoSpacer->changeSize(0, 20, QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
|
||||
m_addInfoTextLabel->setText(m_model->GetAdditionalInfo(modelIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_addInfoTitleLabel->hide();
|
||||
m_addInfoTextLabel->hide();
|
||||
|
||||
m_addInfoSpacer->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
}
|
||||
|
||||
// Included Gems
|
||||
m_includedGems->Update(tr("Included Gems"), "", m_model->GetIncludedGemNames(modelIndex));
|
||||
|
||||
m_mainWidget->adjustSize();
|
||||
m_mainWidget->show();
|
||||
}
|
||||
|
||||
void GemRepoInspector::InitMainWidget()
|
||||
{
|
||||
// Repo name and url link
|
||||
m_nameLabel = new QLabel();
|
||||
m_nameLabel->setObjectName("gemRepoInspectorNameLabel");
|
||||
m_mainLayout->addWidget(m_nameLabel);
|
||||
|
||||
m_repoLinkLabel = new LinkLabel(tr("Repo Url"), QUrl(""), 12, this);
|
||||
m_mainLayout->addWidget(m_repoLinkLabel);
|
||||
m_mainLayout->addSpacing(5);
|
||||
|
||||
// Repo summary
|
||||
m_summaryLabel = new QLabel();
|
||||
m_summaryLabel->setObjectName("gemRepoInspectorBodyLabel");
|
||||
m_summaryLabel->setWordWrap(true);
|
||||
m_summaryLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
m_summaryLabel->setOpenExternalLinks(true);
|
||||
m_mainLayout->addWidget(m_summaryLabel);
|
||||
m_mainLayout->addSpacing(20);
|
||||
|
||||
// Separating line
|
||||
QFrame* hLine = new QFrame();
|
||||
hLine->setFrameShape(QFrame::HLine);
|
||||
hLine->setObjectName("horizontalSeparatingLine");
|
||||
m_mainLayout->addWidget(hLine);
|
||||
m_mainLayout->addSpacing(10);
|
||||
|
||||
// Additional information
|
||||
m_addInfoTitleLabel = new QLabel();
|
||||
m_addInfoTitleLabel->setObjectName("gemRepoInspectorAddInfoTitleLabel");
|
||||
m_addInfoTitleLabel->setText(tr("Additional Information"));
|
||||
m_mainLayout->addWidget(m_addInfoTitleLabel);
|
||||
|
||||
m_addInfoTextLabel = new QLabel();
|
||||
m_addInfoTextLabel->setObjectName("gemRepoInspectorBodyLabel");
|
||||
m_addInfoTextLabel->setWordWrap(true);
|
||||
m_addInfoTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
m_addInfoTextLabel->setOpenExternalLinks(true);
|
||||
m_mainLayout->addWidget(m_addInfoTextLabel);
|
||||
|
||||
// Conditional spacing for additional info section
|
||||
m_addInfoSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding);
|
||||
m_mainLayout->addSpacerItem(m_addInfoSpacer);
|
||||
|
||||
// Included Gems
|
||||
m_includedGems = new GemsSubWidget();
|
||||
m_mainLayout->addWidget(m_includedGems);
|
||||
m_mainLayout->addSpacing(20);
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <GemRepo/GemRepoModel.h>
|
||||
#include <LinkWidget.h>
|
||||
#include <GemsSubWidget.h>
|
||||
|
||||
#include <QItemSelection>
|
||||
#include <QScrollArea>
|
||||
#include <QSpacerItem>
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
|
||||
QT_FORWARD_DECLARE_CLASS(QLabel)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemRepoInspector : public QScrollArea
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public : explicit GemRepoInspector(GemRepoModel* model, QWidget* parent = nullptr);
|
||||
~GemRepoInspector() = default;
|
||||
|
||||
void Update(const QModelIndex& modelIndex);
|
||||
|
||||
private slots:
|
||||
void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
|
||||
private:
|
||||
void InitMainWidget();
|
||||
|
||||
GemRepoModel* m_model = nullptr;
|
||||
QWidget* m_mainWidget = nullptr;
|
||||
QVBoxLayout* m_mainLayout = nullptr;
|
||||
|
||||
// General info section
|
||||
QLabel* m_nameLabel = nullptr;
|
||||
LinkLabel* m_repoLinkLabel = nullptr;
|
||||
QLabel* m_summaryLabel = nullptr;
|
||||
|
||||
// Additional information
|
||||
QLabel* m_addInfoTitleLabel = nullptr;
|
||||
QLabel* m_addInfoTextLabel = nullptr;
|
||||
QSpacerItem* m_addInfoSpacer = nullptr;
|
||||
|
||||
// Included Gems
|
||||
GemsSubWidget* m_includedGems = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -11,13 +11,14 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemRepoListView::GemRepoListView(QAbstractItemModel* model, QWidget* parent)
|
||||
GemRepoListView::GemRepoListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent)
|
||||
: QListView(parent)
|
||||
{
|
||||
setObjectName("gemRepoListView");
|
||||
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
|
||||
setModel(model);
|
||||
setSelectionModel(selectionModel);
|
||||
setItemDelegate(new GemRepoItemDelegate(model, this));
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QListView>
|
||||
#include <QItemSelectionModel>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
|
||||
@@ -22,7 +23,7 @@ namespace O3DE::ProjectManager
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemRepoListView(QAbstractItemModel* model, QWidget* parent = nullptr);
|
||||
explicit GemRepoListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent = nullptr);
|
||||
~GemRepoListView() = default;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
*/
|
||||
|
||||
#include <GemRepo/GemRepoModel.h>
|
||||
#include <PythonBindings.h>
|
||||
|
||||
#include <QItemSelectionModel>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -16,6 +18,7 @@ namespace O3DE::ProjectManager
|
||||
: QStandardItemModel(parent)
|
||||
{
|
||||
m_selectionModel = new QItemSelectionModel(this, parent);
|
||||
m_gemModel = new GemModel(this);
|
||||
}
|
||||
|
||||
QItemSelectionModel* GemRepoModel::GetSelectionModel() const
|
||||
@@ -37,8 +40,17 @@ namespace O3DE::ProjectManager
|
||||
item->setData(gemRepoInfo.m_repoLink, RoleRepoLink);
|
||||
item->setData(gemRepoInfo.m_lastUpdated, RoleLastUpdated);
|
||||
item->setData(gemRepoInfo.m_path, RolePath);
|
||||
item->setData(gemRepoInfo.m_additionalInfo, RoleAdditionalInfo);
|
||||
item->setData(gemRepoInfo.m_includedGemPaths, RoleIncludedGems);
|
||||
|
||||
appendRow(item);
|
||||
|
||||
QVector<GemInfo> includedGemInfos = GetIncludedGemInfos(item->index());
|
||||
|
||||
for (const GemInfo& gemInfo : includedGemInfos)
|
||||
{
|
||||
m_gemModel->AddGem(gemInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void GemRepoModel::Clear()
|
||||
@@ -61,6 +73,11 @@ namespace O3DE::ProjectManager
|
||||
return modelIndex.data(RoleSummary).toString();
|
||||
}
|
||||
|
||||
QString GemRepoModel::GetAdditionalInfo(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleAdditionalInfo).toString();
|
||||
}
|
||||
|
||||
QString GemRepoModel::GetDirectoryLink(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleDirectoryLink).toString();
|
||||
@@ -81,6 +98,45 @@ namespace O3DE::ProjectManager
|
||||
return modelIndex.data(RolePath).toString();
|
||||
}
|
||||
|
||||
QStringList GemRepoModel::GetIncludedGemPaths(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleIncludedGems).toStringList();
|
||||
}
|
||||
|
||||
QStringList GemRepoModel::GetIncludedGemNames(const QModelIndex& modelIndex)
|
||||
{
|
||||
QStringList gemNames;
|
||||
QVector<GemInfo> gemInfos = GetIncludedGemInfos(modelIndex);
|
||||
|
||||
for (const GemInfo& gemInfo : gemInfos)
|
||||
{
|
||||
gemNames.append(gemInfo.m_displayName);
|
||||
}
|
||||
|
||||
return gemNames;
|
||||
}
|
||||
|
||||
QVector<GemInfo> GemRepoModel::GetIncludedGemInfos(const QModelIndex& modelIndex)
|
||||
{
|
||||
QVector<GemInfo> allGemInfos;
|
||||
QStringList repoGemPaths = GetIncludedGemPaths(modelIndex);
|
||||
|
||||
for (const QString& gemPath : repoGemPaths)
|
||||
{
|
||||
AZ::Outcome<GemInfo> gemInfoResult = PythonBindingsInterface::Get()->GetGemInfo(gemPath);
|
||||
if (gemInfoResult.IsSuccess())
|
||||
{
|
||||
allGemInfos.append(gemInfoResult.GetValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(nullptr, tr("Gem Not Found"), tr("Cannot find info for gem %1.").arg(gemPath));
|
||||
}
|
||||
}
|
||||
|
||||
return allGemInfos;
|
||||
}
|
||||
|
||||
bool GemRepoModel::IsEnabled(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleIsEnabled).toBool();
|
||||
@@ -91,4 +147,9 @@ namespace O3DE::ProjectManager
|
||||
model.setData(modelIndex, isEnabled, RoleIsEnabled);
|
||||
}
|
||||
|
||||
bool GemRepoModel::HasAdditionalInfo(const QModelIndex& modelIndex)
|
||||
{
|
||||
return !modelIndex.data(RoleAdditionalInfo).toString().isEmpty();
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QStandardItemModel>
|
||||
#include <GemRepo/GemRepoInfo.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
|
||||
@@ -32,13 +33,19 @@ namespace O3DE::ProjectManager
|
||||
static QString GetName(const QModelIndex& modelIndex);
|
||||
static QString GetCreator(const QModelIndex& modelIndex);
|
||||
static QString GetSummary(const QModelIndex& modelIndex);
|
||||
static QString GetAdditionalInfo(const QModelIndex& modelIndex);
|
||||
static QString GetDirectoryLink(const QModelIndex& modelIndex);
|
||||
static QString GetRepoLink(const QModelIndex& modelIndex);
|
||||
static QDateTime GetLastUpdated(const QModelIndex& modelIndex);
|
||||
static QString GetPath(const QModelIndex& modelIndex);
|
||||
|
||||
static QStringList GetIncludedGemPaths(const QModelIndex& modelIndex);
|
||||
static QStringList GetIncludedGemNames(const QModelIndex& modelIndex);
|
||||
static QVector<GemInfo> GetIncludedGemInfos(const QModelIndex& modelIndex);
|
||||
|
||||
static bool IsEnabled(const QModelIndex& modelIndex);
|
||||
static void SetEnabled(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isEnabled);
|
||||
static bool HasAdditionalInfo(const QModelIndex& modelIndex);
|
||||
|
||||
private:
|
||||
enum UserRole
|
||||
@@ -50,9 +57,13 @@ namespace O3DE::ProjectManager
|
||||
RoleDirectoryLink,
|
||||
RoleRepoLink,
|
||||
RoleLastUpdated,
|
||||
RolePath
|
||||
RolePath,
|
||||
RoleAdditionalInfo,
|
||||
RoleIncludedGems,
|
||||
};
|
||||
|
||||
QItemSelectionModel* m_selectionModel = nullptr;
|
||||
|
||||
GemModel* m_gemModel = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <GemRepo/GemRepoItemDelegate.h>
|
||||
#include <GemRepo/GemRepoListView.h>
|
||||
#include <GemRepo/GemRepoModel.h>
|
||||
#include <GemRepo/GemRepoInspector.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
@@ -40,10 +41,6 @@ namespace O3DE::ProjectManager
|
||||
|
||||
hLayout->addSpacing(60);
|
||||
|
||||
m_gemRepoInspector = new QFrame(this);
|
||||
m_gemRepoInspector->setObjectName(tr("gemRepoInspector"));
|
||||
m_gemRepoInspector->setFixedWidth(240);
|
||||
|
||||
QVBoxLayout* middleVLayout = new QVBoxLayout();
|
||||
middleVLayout->setMargin(0);
|
||||
middleVLayout->setSpacing(0);
|
||||
@@ -99,10 +96,13 @@ namespace O3DE::ProjectManager
|
||||
m_gemRepoHeaderTable->horizontalHeader()->setStyleSheet("QHeaderView::section { background-color:transparent; color:white; font-size:12px; text-align:left; border-style:none; }");
|
||||
middleVLayout->addWidget(m_gemRepoHeaderTable);
|
||||
|
||||
m_gemRepoListView = new GemRepoListView(m_gemRepoModel, this);
|
||||
m_gemRepoListView = new GemRepoListView(m_gemRepoModel, m_gemRepoModel->GetSelectionModel(), this);
|
||||
middleVLayout->addWidget(m_gemRepoListView);
|
||||
|
||||
hLayout->addLayout(middleVLayout);
|
||||
|
||||
m_gemRepoInspector = new GemRepoInspector(m_gemRepoModel, this);
|
||||
m_gemRepoInspector->setFixedWidth(240);
|
||||
hLayout->addWidget(m_gemRepoInspector);
|
||||
|
||||
Reinit();
|
||||
@@ -134,7 +134,7 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str()));
|
||||
QMessageBox::critical(this, tr("Operation failed"), tr("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ QT_FORWARD_DECLARE_CLASS(QTableWidget)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
QT_FORWARD_DECLARE_CLASS(GemRepoInspector)
|
||||
QT_FORWARD_DECLARE_CLASS(GemRepoListView)
|
||||
QT_FORWARD_DECLARE_CLASS(GemRepoModel)
|
||||
|
||||
@@ -40,7 +41,7 @@ namespace O3DE::ProjectManager
|
||||
QTableWidget* m_gemRepoHeaderTable = nullptr;
|
||||
QHeaderView* m_gemRepoListHeader = nullptr;
|
||||
GemRepoListView* m_gemRepoListView = nullptr;
|
||||
QFrame* m_gemRepoInspector = nullptr;
|
||||
GemRepoInspector* m_gemRepoInspector = nullptr;
|
||||
GemRepoModel* m_gemRepoModel = nullptr;
|
||||
|
||||
QLabel* m_lastAllUpdateLabel;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 <GemsSubWidget.h>
|
||||
#include <TagWidget.h>
|
||||
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemsSubWidget::GemsSubWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_layout = new QVBoxLayout();
|
||||
m_layout->setAlignment(Qt::AlignTop);
|
||||
m_layout->setMargin(0);
|
||||
setLayout(m_layout);
|
||||
|
||||
m_titleLabel = new QLabel();
|
||||
m_titleLabel->setObjectName("gemSubWidgetTitleLabel");
|
||||
m_layout->addWidget(m_titleLabel);
|
||||
|
||||
m_textLabel = new QLabel();
|
||||
m_textLabel->setObjectName("gemSubWidgetTextLabel");
|
||||
m_textLabel->setWordWrap(true);
|
||||
m_layout->addWidget(m_textLabel);
|
||||
|
||||
m_tagWidget = new TagContainerWidget();
|
||||
m_layout->addWidget(m_tagWidget);
|
||||
}
|
||||
|
||||
void GemsSubWidget::Update(const QString& title, const QString& text, const QStringList& gemNames)
|
||||
{
|
||||
m_titleLabel->setText(title);
|
||||
m_textLabel->setText(text);
|
||||
m_tagWidget->Update(gemNames);
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QWidget>
|
||||
#include <TagWidget.h>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
|
||||
QT_FORWARD_DECLARE_CLASS(QLabel)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
// Title, description and tag widget container used for the depending and conflicting gems
|
||||
class GemsSubWidget
|
||||
: public QWidget
|
||||
{
|
||||
public:
|
||||
GemsSubWidget(QWidget* parent = nullptr);
|
||||
void Update(const QString& title, const QString& text, const QStringList& gemNames);
|
||||
|
||||
private:
|
||||
QLabel* m_titleLabel = nullptr;
|
||||
QLabel* m_textLabel = nullptr;
|
||||
QVBoxLayout* m_layout = nullptr;
|
||||
TagContainerWidget* m_tagWidget = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -14,9 +14,10 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
LinkLabel::LinkLabel(const QString& text, const QUrl& url, QWidget* parent)
|
||||
LinkLabel::LinkLabel(const QString& text, const QUrl& url, int fontSize, QWidget* parent)
|
||||
: QLabel(text, parent)
|
||||
, m_url(url)
|
||||
, m_fontSize(fontSize)
|
||||
{
|
||||
SetDefaultStyle();
|
||||
}
|
||||
@@ -33,7 +34,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void LinkLabel::enterEvent([[maybe_unused]] QEvent* event)
|
||||
{
|
||||
setStyleSheet("font-size: 10px; color: #94D2FF; text-decoration: underline;");
|
||||
setStyleSheet(QString("font-size: %1px; color: #94D2FF; text-decoration: underline;").arg(m_fontSize));
|
||||
}
|
||||
|
||||
void LinkLabel::leaveEvent([[maybe_unused]] QEvent* event)
|
||||
@@ -48,6 +49,6 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void LinkLabel::SetDefaultStyle()
|
||||
{
|
||||
setStyleSheet("font-size: 10px; color: #94D2FF;");
|
||||
setStyleSheet(QString("font-size: %1px; color: #94D2FF;").arg(m_fontSize));
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace O3DE::ProjectManager
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
LinkLabel(const QString& text = {}, const QUrl& url = {}, QWidget* parent = nullptr);
|
||||
LinkLabel(const QString& text = {}, const QUrl& url = {}, int fontSize = 10, QWidget* parent = nullptr);
|
||||
|
||||
void SetUrl(const QUrl& url);
|
||||
|
||||
@@ -40,5 +40,6 @@ namespace O3DE::ProjectManager
|
||||
|
||||
private:
|
||||
QUrl m_url;
|
||||
int m_fontSize;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -675,6 +675,14 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
if (data.contains("dependencies"))
|
||||
{
|
||||
for (auto dependency : data["dependencies"])
|
||||
{
|
||||
gemInfo.m_dependencies.push_back(Py_To_String(dependency));
|
||||
}
|
||||
}
|
||||
|
||||
QString gemType = Py_To_String_Optional(data, "type", "");
|
||||
if (gemType == "Asset")
|
||||
{
|
||||
@@ -946,8 +954,16 @@ namespace O3DE::ProjectManager
|
||||
return AZ::Failure<AZStd::string>(result.GetError().c_str());
|
||||
}
|
||||
#else
|
||||
gemRepos.push_back(GemRepoInfo("JohnCreates", "John Smith", "", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true));
|
||||
gemRepos.push_back(GemRepoInfo("JanesGems", "Jane Doe", "", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false));
|
||||
GemRepoInfo mockJohnRepo("JohnCreates", "John Smith", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true);
|
||||
mockJohnRepo.m_summary = "John's Summary. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitudin dapibus urna";
|
||||
mockJohnRepo.m_repoLink = "https://github.com/o3de/o3de";
|
||||
mockJohnRepo.m_additionalInfo = "John's additional info. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitu.";
|
||||
gemRepos.push_back(mockJohnRepo);
|
||||
|
||||
GemRepoInfo mockJaneRepo("JanesGems", "Jane Doe", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false);
|
||||
mockJaneRepo.m_summary = "Jane's Summary.";
|
||||
mockJaneRepo.m_repoLink = "https://github.com/o3de/o3de.org";
|
||||
gemRepos.push_back(mockJaneRepo);
|
||||
#endif // MOCK_GEM_REPO_INFO
|
||||
|
||||
std::sort(gemRepos.begin(), gemRepos.end());
|
||||
|
||||
@@ -56,8 +56,9 @@ namespace O3DE::ProjectManager
|
||||
// Gems
|
||||
|
||||
/**
|
||||
* Get info about a Gem
|
||||
* @param projectPath the absolute path to the Gem
|
||||
* Get info about a Gem.
|
||||
* @param path The absolute path to the Gem
|
||||
* @param projectPath (Optional) The absolute path to the Gem project
|
||||
* @return an outcome with GemInfo on success
|
||||
*/
|
||||
virtual AZ::Outcome<GemInfo> GetGemInfo(const QString& path, const QString& projectPath = {}) = 0;
|
||||
|
||||
@@ -27,6 +27,8 @@ set(FILES
|
||||
Source/FormFolderBrowseEditWidget.cpp
|
||||
Source/FormImageBrowseEditWidget.h
|
||||
Source/FormImageBrowseEditWidget.cpp
|
||||
Source/GemsSubWidget.h
|
||||
Source/GemsSubWidget.cpp
|
||||
Source/PathValidator.h
|
||||
Source/PathValidator.cpp
|
||||
Source/ProjectManagerWindow.h
|
||||
@@ -104,6 +106,8 @@ set(FILES
|
||||
Source/GemRepo/GemRepoScreen.cpp
|
||||
Source/GemRepo/GemRepoInfo.h
|
||||
Source/GemRepo/GemRepoInfo.cpp
|
||||
Source/GemRepo/GemRepoInspector.h
|
||||
Source/GemRepo/GemRepoInspector.cpp
|
||||
Source/GemRepo/GemRepoItemDelegate.h
|
||||
Source/GemRepo/GemRepoItemDelegate.cpp
|
||||
Source/GemRepo/GemRepoListView.h
|
||||
|
||||
@@ -11,6 +11,7 @@ set(FILES
|
||||
Resources/ProjectManager.qss
|
||||
tests/ApplicationTests.cpp
|
||||
tests/PythonBindingsTests.cpp
|
||||
tests/GemCatalogTests.cpp
|
||||
tests/main.cpp
|
||||
tests/UtilsTests.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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/UnitTest/TestTypes.h>
|
||||
#include <AzTest/Utils.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemCatalogTests
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
|
||||
GemCatalogTests() = default;
|
||||
};
|
||||
|
||||
TEST_F(GemCatalogTests, GemCatalog_Displays_But_Does_Not_Add_Dependencies)
|
||||
{
|
||||
GemModel* gemModel = new GemModel();
|
||||
|
||||
// given 3 gems a,b,c where a depends on b which depends on c
|
||||
GemInfo gemA, gemB, gemC;
|
||||
QModelIndex indexA, indexB, indexC;
|
||||
gemA.m_name = "a";
|
||||
gemB.m_name = "b";
|
||||
gemC.m_name = "c";
|
||||
|
||||
gemA.m_dependencies = QStringList({ "b" });
|
||||
gemB.m_dependencies = QStringList({ "c" });
|
||||
|
||||
gemModel->AddGem(gemA);
|
||||
indexA = gemModel->FindIndexByNameString(gemA.m_name);
|
||||
|
||||
gemModel->AddGem(gemB);
|
||||
indexB = gemModel->FindIndexByNameString(gemB.m_name);
|
||||
|
||||
gemModel->AddGem(gemC);
|
||||
indexC = gemModel->FindIndexByNameString(gemC.m_name);
|
||||
|
||||
gemModel->UpdateGemDependencies();
|
||||
|
||||
EXPECT_FALSE(GemModel::IsAdded(indexA));
|
||||
EXPECT_FALSE(GemModel::IsAddedDependency(indexB) || GemModel::IsAddedDependency(indexC));
|
||||
|
||||
// when a is added
|
||||
GemModel::SetIsAdded(*gemModel, indexA, true);
|
||||
|
||||
// expect b and c are now dependencies of an added gem but not themselves added
|
||||
// cmake will handle dependencies
|
||||
EXPECT_TRUE(GemModel::IsAddedDependency(indexB) && GemModel::IsAddedDependency(indexC));
|
||||
EXPECT_TRUE(!GemModel::IsAdded(indexB) && !GemModel::IsAdded(indexC));
|
||||
|
||||
QVector<QModelIndex> gemsToAdd = gemModel->GatherGemsToBeAdded();
|
||||
EXPECT_TRUE(gemsToAdd.size() == 1);
|
||||
EXPECT_EQ(GemModel::GetName(gemsToAdd.at(0)), gemA.m_name);
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <AzslCompiler.h>
|
||||
|
||||
#include "ShaderPlatformInterfaceRequest.h"
|
||||
#include "ShaderBuilder_Traits_Platform.h"
|
||||
#include "AtomShaderConfig.h"
|
||||
|
||||
#include "SrgLayoutUtility.h"
|
||||
@@ -456,8 +457,9 @@ namespace AZ
|
||||
const uint32_t rhiUniqueIndex, const AZStd::string& platformIdentifier, const AZStd::string& shaderJsonPath,
|
||||
const uint32_t supervariantIndex, RPI::ShaderAssetSubId shaderAssetSubId)
|
||||
{
|
||||
// platform id from identifier
|
||||
AzFramework::PlatformId platformId = AzFramework::PlatformId::PC;
|
||||
// Define a fallback platform ID based on the current host platform
|
||||
AzFramework::PlatformId platformId = AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM;
|
||||
|
||||
if (platformIdentifier == "pc")
|
||||
{
|
||||
platformId = AzFramework::PlatformId::PC;
|
||||
@@ -478,6 +480,10 @@ namespace AZ
|
||||
{
|
||||
platformId = AzFramework::PlatformId::IOS;
|
||||
}
|
||||
else if (platformIdentifier == "server")
|
||||
{
|
||||
platformId = AzFramework::PlatformId::SERVER;
|
||||
}
|
||||
|
||||
uint32_t assetSubId = RPI::ShaderAsset::MakeProductAssetSubId(rhiUniqueIndex, supervariantIndex, aznumeric_cast<uint32_t>(shaderAssetSubId));
|
||||
auto assetIdOutcome = RPI::AssetUtils::MakeAssetId(shaderJsonPath, assetSubId);
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_ATOM_SHADERBUILDER_AZSLC UNUSED_TRAIT
|
||||
#define AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM UNUSED_TRAIT
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_ATOM_SHADERBUILDER_AZSLC "azslc"
|
||||
|
||||
#define AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM AzFramework::PlatformId::LINUX_ID
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_ATOM_SHADERBUILDER_AZSLC "azslc"
|
||||
#define AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM AzFramework::PlatformId::MAC_ID
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_ATOM_SHADERBUILDER_AZSLC "azslc.exe"
|
||||
#define AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM AzFramework::PlatformId::PC
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_ATOM_SHADERBUILDER_AZSLC UNUSED_TRAIT
|
||||
#define AZ_TRAIT_ATOM_FALLBACK_ASSET_HOST_PLATFORM UNUSED_TRAIT
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
#include "AuxGeomDrawQueue.h"
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "DynamicPrimitiveProcessor.h"
|
||||
#include "FixedShapeProcessor.h"
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "DynamicPrimitiveProcessor.h"
|
||||
#include "AuxGeomDrawProcessorShared.h"
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/DrawPacketBuilder.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
|
||||
@@ -21,6 +20,8 @@
|
||||
#include <Atom/RPI.Public/Shader/Shader.h>
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/DrawPacketBuilder.h>
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <Atom/Feature/CoreLights/CoreLightsConstants.h>
|
||||
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
|
||||
#include <Atom/RPI.Public/ColorManagement/TransformColor.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <CoreLights/Shadow.h>
|
||||
#include <Math/GaussianMathFilter.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RPI.Public/AuxGeom/AuxGeomDraw.h>
|
||||
#include <Atom/RPI.Public/ColorManagement/TransformColor.h>
|
||||
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <Atom/Feature/CoreLights/CoreLightsConstants.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
|
||||
#include <Atom/RPI.Public/ColorManagement/TransformColor.h>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <Atom/Feature/CoreLights/CoreLightsConstants.h>
|
||||
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
|
||||
#include <Atom/RPI.Public/ColorManagement/TransformColor.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <Atom/Feature/CoreLights/CoreLightsConstants.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
|
||||
#include <Atom/RPI.Public/ColorManagement/TransformColor.h>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <Atom/Feature/CoreLights/CoreLightsConstants.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
|
||||
#include <Atom/RPI.Public/ColorManagement/TransformColor.h>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <Atom/Feature/CoreLights/CoreLightsConstants.h>
|
||||
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
|
||||
#include <Atom/RPI.Public/ColorManagement/TransformColor.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <Atom/Feature/CoreLights/CoreLightsConstants.h>
|
||||
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
|
||||
#include <Atom/RPI.Public/ColorManagement/TransformColor.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
|
||||
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#include <AtomCore/Instance/InstanceDatabase.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/CommandList.h>
|
||||
|
||||
#include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
|
||||
|
||||
-2
@@ -11,8 +11,6 @@
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/Image/StreamingImage.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
|
||||
namespace AZ
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <RenderCommon.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/RHIUtils.h>
|
||||
#include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
|
||||
#include <Atom/Feature/Mesh/MeshFeatureProcessor.h>
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
#include <PostProcess/PostProcessFeatureProcessor.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
|
||||
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include <Atom/RHI/Factory.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
|
||||
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "ProfilingCaptureSystemComponent.h"
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/CpuProfilerImpl.h>
|
||||
#include <Atom/RHI/RHIUtils.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
|
||||
#include <Atom/Feature/Utils/ProfilingCaptureBus.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <RayTracing/RayTracingFeatureProcessor.h>
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
#include <Atom/Feature/TransformService/TransformServiceFeatureProcessor.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
@@ -105,14 +104,31 @@ namespace AZ
|
||||
m_meshes[objectIndex].m_subMeshes = subMeshes;
|
||||
}
|
||||
|
||||
Mesh& mesh = m_meshes[objectIndex];
|
||||
|
||||
// search for an existing BLAS instance entry for this mesh using the assetId
|
||||
BlasInstanceMap::iterator itMeshBlasInstance = m_blasInstanceMap.find(assetId);
|
||||
if (itMeshBlasInstance == m_blasInstanceMap.end())
|
||||
{
|
||||
// make a new BLAS map entry for this mesh
|
||||
MeshBlasInstance meshBlasInstance;
|
||||
meshBlasInstance.m_count = 1;
|
||||
meshBlasInstance.m_subMeshes.reserve(mesh.m_subMeshes.size());
|
||||
itMeshBlasInstance = m_blasInstanceMap.insert({ assetId, meshBlasInstance }).first;
|
||||
}
|
||||
else
|
||||
{
|
||||
itMeshBlasInstance->second.m_count++;
|
||||
}
|
||||
|
||||
// create the BLAS buffers for each sub-mesh, or re-use existing BLAS objects if they were already created.
|
||||
// Note: all sub-meshes must either create new BLAS objects or re-use existing ones, otherwise it's an error (it's the same model in both cases)
|
||||
// Note: the buffer is just reserved here, the BLAS is built in the RayTracingAccelerationStructurePass
|
||||
Mesh& mesh = m_meshes[objectIndex];
|
||||
bool blasInstanceFound = false;
|
||||
|
||||
for (auto& subMesh : mesh.m_subMeshes)
|
||||
for (uint32_t subMeshIndex = 0; subMeshIndex < mesh.m_subMeshes.size(); ++subMeshIndex)
|
||||
{
|
||||
SubMesh& subMesh = mesh.m_subMeshes[subMeshIndex];
|
||||
|
||||
RHI::RayTracingBlasDescriptor blasDescriptor;
|
||||
blasDescriptor.Build()
|
||||
->Geometry()
|
||||
@@ -121,13 +137,11 @@ namespace AZ
|
||||
->IndexBuffer(subMesh.m_indexBufferView)
|
||||
;
|
||||
|
||||
// search for an existing BLAS object for this model
|
||||
RayTracingBlasMap::iterator itBlas = m_blasMap.find(assetId);
|
||||
if (itBlas != m_blasMap.end())
|
||||
// determine if we have an existing BLAS object for this subMesh
|
||||
if (itMeshBlasInstance->second.m_subMeshes.size() >= subMeshIndex + 1)
|
||||
{
|
||||
// re-use existing BLAS
|
||||
subMesh.m_blas = itBlas->second.m_blas;
|
||||
itBlas->second.m_count++;
|
||||
subMesh.m_blas = itMeshBlasInstance->second.m_subMeshes[subMeshIndex].m_blas;
|
||||
|
||||
// keep track of the fact that we re-used a BLAS
|
||||
blasInstanceFound = true;
|
||||
@@ -143,8 +157,7 @@ namespace AZ
|
||||
subMesh.m_blas->CreateBuffers(*device, &blasDescriptor, *m_bufferPools);
|
||||
|
||||
// store the BLAS in the side list
|
||||
RayTracingBlasInstance blasInstance = { subMesh.m_blas, 1 };
|
||||
m_blasMap.insert({ assetId, blasInstance });
|
||||
itMeshBlasInstance->second.m_subMeshes.push_back({ subMesh.m_blas });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,16 +195,16 @@ namespace AZ
|
||||
m_meshes.erase(itMesh);
|
||||
m_revision++;
|
||||
|
||||
// decrement the count from the BLAS instance, and check to see if we can remove it
|
||||
RayTracingBlasMap::iterator itBlas = m_blasMap.find(itMesh->second.m_assetId);
|
||||
if (itBlas != m_blasMap.end())
|
||||
// decrement the count from the BLAS instances, and check to see if we can remove them
|
||||
BlasInstanceMap::iterator itBlas = m_blasInstanceMap.find(itMesh->second.m_assetId);
|
||||
if (itBlas != m_blasInstanceMap.end())
|
||||
{
|
||||
itBlas->second.m_count--;
|
||||
if (itBlas->second.m_count == 0)
|
||||
{
|
||||
m_blasMap.erase(itBlas);
|
||||
m_blasInstanceMap.erase(itBlas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_meshInfoBufferNeedsUpdate = true;
|
||||
|
||||
@@ -268,14 +268,19 @@ namespace AZ
|
||||
bool m_materialInfoBufferNeedsUpdate = false;
|
||||
|
||||
// side list for looking up existing BLAS objects so they can be re-used when the same mesh is added multiple times
|
||||
struct RayTracingBlasInstance
|
||||
struct SubMeshBlasInstance
|
||||
{
|
||||
RHI::Ptr<RHI::RayTracingBlas> m_blas;
|
||||
uint32_t m_count = 0;
|
||||
};
|
||||
|
||||
using RayTracingBlasMap = AZStd::unordered_map<AZ::Data::AssetId, RayTracingBlasInstance>;
|
||||
RayTracingBlasMap m_blasMap;
|
||||
struct MeshBlasInstance
|
||||
{
|
||||
uint32_t m_count = 0;
|
||||
AZStd::vector<SubMeshBlasInstance> m_subMeshes;
|
||||
};
|
||||
|
||||
using BlasInstanceMap = AZStd::unordered_map<AZ::Data::AssetId, MeshBlasInstance>;
|
||||
BlasInstanceMap m_blasInstanceMap;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -13,7 +13,6 @@
|
||||
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
||||
#include <Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h>
|
||||
#include <Atom/Feature/Mesh/MeshFeatureProcessor.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
#include <Atom/RHI/PipelineState.h>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <Math/GaussianMathFilter.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <Atom/RPI.Public/Shader/Shader.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/CommandList.h>
|
||||
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/DrawPacketBuilder.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
|
||||
-1
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <Atom/Feature/TransformService/TransformServiceFeatureProcessor.h>
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/FreeListAllocator.h>
|
||||
#include <Atom/RHI/PoolAllocator.h>
|
||||
#include <Atom/RHI/MemoryAllocation.h>
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Object.h>
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <Atom/RHI/BufferPool.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/MemoryStatisticsBuilder.h>
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
*/
|
||||
|
||||
#include <Atom/RHI/CommandQueue.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Device.h>
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RHI
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Device.h>
|
||||
#include <Atom/RHI/MemoryStatisticsBus.h>
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include <Atom/RHI/Fence.h>
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RHI
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <Atom/RHI/BufferFrameAttachment.h>
|
||||
#include <Atom/RHI/BufferPoolBase.h>
|
||||
#include <Atom/RHI/BufferScopeAttachment.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/FrameGraph.h>
|
||||
#include <Atom/RHI/ImageFrameAttachment.h>
|
||||
#include <Atom/RHI/ImagePoolBase.h>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/FrameGraphCompiler.h>
|
||||
#include <Atom/RHI/BufferFrameAttachment.h>
|
||||
#include <Atom/RHI/BufferScopeAttachment.h>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*
|
||||
*/
|
||||
#include <Atom/RHI/Buffer.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/FrameGraphExecuteGroup.h>
|
||||
#include <Atom/RHI/FrameGraphExecuter.h>
|
||||
#include <Atom/RHI/FrameGraph.h>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/FrameScheduler.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/FrameEventBus.h>
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/PipelineStateCache.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/std/sort.h>
|
||||
#include <AzCore/std/parallel/exponential_backoff.h>
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/Device.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/RHISystem.h>
|
||||
#include <Atom/RHI/RHIUtils.h>
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <RHI/CommandList.h>
|
||||
#include <RHI/Conversions.h>
|
||||
#include <RHI/DescriptorContext.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
|
||||
namespace AZ
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
|
||||
#include <Atom/RHI/Device.h>
|
||||
#include <Atom/RHI.Reflect/CpuTimingStatistics.h>
|
||||
#include <AzCore/Debug/EventTraceDrillerBus.h>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <RHI/Conversions.h>
|
||||
#include <RHI/Device.h>
|
||||
#include <RHI/Image.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI.Reflect/DX12/PlatformLimitsDescriptor.h>
|
||||
|
||||
namespace AZ
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user