Merge branch 'development' of https://github.com/aws-lumberyard-dev/o3de into lytt_linux_tests
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
<svg width="24" height="33" viewBox="0 0 24 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5" y="7" width="2" height="12" fill="#808080"/>
|
||||
<rect x="5" y="19" width="2" height="14" fill="#808080"/>
|
||||
<rect x="17" y="16" width="2" height="12" transform="rotate(90 17 16)" fill="#808080"/>
|
||||
<circle cx="6" cy="6" r="2" fill="#808080"/>
|
||||
<circle cx="18" cy="17" r="2" fill="#808080"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 398 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5" width="2" height="12" fill="grey"/>
|
||||
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="grey"/>
|
||||
<circle cx="18" cy="13" r="2" fill="grey"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 280 B |
@@ -0,0 +1,6 @@
|
||||
<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5" width="2" height="12" fill="grey"/>
|
||||
<rect x="5" y="14" width="2" height="12" fill="grey"/>
|
||||
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="grey"/>
|
||||
<circle cx="18" cy="13" r="2" fill="grey"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 335 B |
@@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5" y="7" width="2" height="7" fill="#808080"/>
|
||||
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="#808080"/>
|
||||
<circle cx="6" cy="6" r="2" fill="#808080"/>
|
||||
<circle cx="18" cy="13" r="2" fill="#808080"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 339 B |
@@ -8098,7 +8098,7 @@
|
||||
</message>
|
||||
<message 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,
|
||||
|
||||
@@ -141,6 +141,10 @@ AzAssetBrowserWindow::AzAssetBrowserWindow(QWidget* parent)
|
||||
m_ui->m_assetBrowserTreeViewWidget, &AzAssetBrowser::AssetBrowserTreeView::ClearTypeFilter, m_ui->m_searchWidget,
|
||||
&AzAssetBrowser::SearchWidget::ClearTypeFilter);
|
||||
|
||||
connect(
|
||||
this, &AzAssetBrowserWindow::SizeChangedSignal, m_ui->m_assetBrowserTableViewWidget,
|
||||
&AzAssetBrowser::AssetBrowserTableView::UpdateSizeSlot);
|
||||
|
||||
m_ui->m_assetBrowserTreeViewWidget->SetName("AssetBrowserTreeView_main");
|
||||
}
|
||||
|
||||
@@ -164,6 +168,25 @@ QObject* AzAssetBrowserWindow::createListenerForShowAssetEditorEvent(QObject* pa
|
||||
return listener;
|
||||
}
|
||||
|
||||
void AzAssetBrowserWindow::resizeEvent(QResizeEvent* resizeEvent)
|
||||
{
|
||||
// leftLayout is the parent of the tableView
|
||||
// rightLayout is the parent of the preview window.
|
||||
// Workaround: When docking windows this event keeps holding the old size of the widgets instead of the new one
|
||||
// but the resizeEvent holds the new size of the whole widget
|
||||
// So we have to save the proportions somehow
|
||||
const QWidget* leftLayout = m_ui->m_leftLayout;
|
||||
const QVBoxLayout* rightLayout = m_ui->m_rightLayout;
|
||||
|
||||
const float oldLeftLayoutWidth = aznumeric_cast<float>(leftLayout->geometry().width());
|
||||
const float oldWidth = aznumeric_cast<float>(leftLayout->geometry().width() + rightLayout->geometry().width());
|
||||
|
||||
const float newWidth = oldLeftLayoutWidth * aznumeric_cast<float>(resizeEvent->size().width()) / oldWidth;
|
||||
|
||||
emit SizeChangedSignal(aznumeric_cast<int>(newWidth));
|
||||
QWidget::resizeEvent(resizeEvent);
|
||||
}
|
||||
|
||||
void AzAssetBrowserWindow::OnInitViewToggleButton()
|
||||
{
|
||||
CreateSwitchViewMenu();
|
||||
|
||||
@@ -53,9 +53,17 @@ public:
|
||||
|
||||
static QObject* createListenerForShowAssetEditorEvent(QObject* parent);
|
||||
|
||||
|
||||
Q_SIGNALS:
|
||||
void SizeChangedSignal(int newWidth);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* resizeEvent) override;
|
||||
|
||||
private:
|
||||
void OnInitViewToggleButton();
|
||||
void UpdateDisplayInfo();
|
||||
|
||||
protected slots:
|
||||
void CreateSwitchViewMenu();
|
||||
void SetExpandedAssetBrowserMode();
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "QtEditorApplication.h"
|
||||
|
||||
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
#include <AzFramework/API/ApplicationAPI_Linux.h>
|
||||
#include <AzFramework/XcbEventHandler.h>
|
||||
#endif
|
||||
|
||||
namespace Editor
|
||||
@@ -19,7 +19,7 @@ namespace Editor
|
||||
if (GetIEditor()->IsInGameMode())
|
||||
{
|
||||
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
AzFramework::LinuxXcbEventHandlerBus::Broadcast(&AzFramework::LinuxXcbEventHandler::HandleXcbEvent, static_cast<xcb_generic_event_t*>(message));
|
||||
AzFramework::XcbEventHandlerBus::Broadcast(&AzFramework::XcbEventHandler::HandleXcbEvent, static_cast<xcb_generic_event_t*>(message));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2428,7 +2428,7 @@ void EditorViewportWidget::RestoreViewportAfterGameMode()
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("CryLegacy", false, "Not restoring the editor viewport camera is currently unsupported");
|
||||
AZ_Warning("CryLegacy", false, "Not restoring the editor viewport camera is currently unsupported");
|
||||
SetViewTM(preGameModeViewTM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -28,34 +28,10 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
InputChannelId::InputChannelId(const char* name)
|
||||
: m_crc32(name)
|
||||
{
|
||||
memset(m_name, 0, AZ_ARRAY_SIZE(m_name));
|
||||
azstrncpy(m_name, NAME_BUFFER_SIZE, name, MAX_NAME_LENGTH);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
InputChannelId::InputChannelId(const InputChannelId& other)
|
||||
: m_crc32(other.m_crc32)
|
||||
{
|
||||
memset(m_name, 0, AZ_ARRAY_SIZE(m_name));
|
||||
azstrcpy(m_name, NAME_BUFFER_SIZE, other.m_name);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
InputChannelId& InputChannelId::operator=(const InputChannelId& other)
|
||||
{
|
||||
azstrcpy(m_name, NAME_BUFFER_SIZE, other.m_name);
|
||||
m_crc32 = other.m_crc32;
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const char* InputChannelId::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
return m_name.c_str();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include <AzCore/std/hash.h>
|
||||
#include <AzCore/std/string/fixed_string.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
namespace AzFramework
|
||||
@@ -22,8 +23,7 @@ namespace AzFramework
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constants
|
||||
static const int NAME_BUFFER_SIZE = 64;
|
||||
static const int MAX_NAME_LENGTH = NAME_BUFFER_SIZE - 1;
|
||||
static constexpr int MAX_NAME_LENGTH = 64;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Allocator
|
||||
@@ -39,21 +39,28 @@ namespace AzFramework
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! Constructor
|
||||
//! \param[in] name Name of the input channel (will be truncated if exceeds MAX_NAME_LENGTH)
|
||||
explicit InputChannelId(const char* name = "");
|
||||
//! \param[in] name Name of the input channel (will be ignored if exceeds MAX_NAME_LENGTH)
|
||||
explicit constexpr InputChannelId(AZStd::string_view name = "")
|
||||
: m_name(name)
|
||||
, m_crc32(name)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! Copy constructor
|
||||
//! \param[in] other Another instance of the class to copy from
|
||||
InputChannelId(const InputChannelId& other);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! Copy assignment operator
|
||||
//! \param[in] other Another instance of the class to copy from
|
||||
InputChannelId& operator=(const InputChannelId& other);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! Default destructor
|
||||
constexpr InputChannelId(const InputChannelId& other) = default;
|
||||
constexpr InputChannelId(InputChannelId&& other) = default;
|
||||
constexpr InputChannelId& operator=(const InputChannelId& other)
|
||||
{
|
||||
m_name = other.m_name;
|
||||
m_crc32 = other.m_crc32;
|
||||
return *this;
|
||||
}
|
||||
constexpr InputChannelId& operator=(InputChannelId&& other)
|
||||
{
|
||||
m_name = AZStd::move(other.m_name);
|
||||
m_crc32 = AZStd::move(other.m_crc32);
|
||||
other.m_crc32 = 0;
|
||||
return *this;
|
||||
}
|
||||
~InputChannelId() = default;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -77,7 +84,7 @@ namespace AzFramework
|
||||
private:
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Variables
|
||||
char m_name[NAME_BUFFER_SIZE]; //!< Name of the input channel
|
||||
AZStd::fixed_string<MAX_NAME_LENGTH> m_name; //!< Name of the input channel
|
||||
AZ::Crc32 m_crc32; //!< Crc32 of the input channel
|
||||
};
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -28,91 +28,6 @@ namespace AzFramework
|
||||
return (inputDeviceId.GetNameCrc32() == IdForIndex0.GetNameCrc32());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceGamepad::Button::A("gamepad_button_a");
|
||||
const InputChannelId InputDeviceGamepad::Button::B("gamepad_button_b");
|
||||
const InputChannelId InputDeviceGamepad::Button::X("gamepad_button_x");
|
||||
const InputChannelId InputDeviceGamepad::Button::Y("gamepad_button_y");
|
||||
const InputChannelId InputDeviceGamepad::Button::L1("gamepad_button_l1");
|
||||
const InputChannelId InputDeviceGamepad::Button::R1("gamepad_button_r1");
|
||||
const InputChannelId InputDeviceGamepad::Button::L3("gamepad_button_l3");
|
||||
const InputChannelId InputDeviceGamepad::Button::R3("gamepad_button_r3");
|
||||
const InputChannelId InputDeviceGamepad::Button::DU("gamepad_button_d_up");
|
||||
const InputChannelId InputDeviceGamepad::Button::DD("gamepad_button_d_down");
|
||||
const InputChannelId InputDeviceGamepad::Button::DL("gamepad_button_d_left");
|
||||
const InputChannelId InputDeviceGamepad::Button::DR("gamepad_button_d_right");
|
||||
const InputChannelId InputDeviceGamepad::Button::Start("gamepad_button_start");
|
||||
const InputChannelId InputDeviceGamepad::Button::Select("gamepad_button_select");
|
||||
const AZStd::array<InputChannelId, 14> InputDeviceGamepad::Button::All =
|
||||
{{
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
L1,
|
||||
R1,
|
||||
L3,
|
||||
R3,
|
||||
DU,
|
||||
DD,
|
||||
DL,
|
||||
DR,
|
||||
Start,
|
||||
Select
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceGamepad::Trigger::L2("gamepad_trigger_l2");
|
||||
const InputChannelId InputDeviceGamepad::Trigger::R2("gamepad_trigger_r2");
|
||||
const AZStd::array<InputChannelId, 2> InputDeviceGamepad::Trigger::All =
|
||||
{{
|
||||
L2,
|
||||
R2
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickAxis2D::L("gamepad_thumbstick_l");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickAxis2D::R("gamepad_thumbstick_r");
|
||||
const AZStd::array<InputChannelId, 2> InputDeviceGamepad::ThumbStickAxis2D::All =
|
||||
{{
|
||||
L,
|
||||
R
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::LX("gamepad_thumbstick_l_x");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::LY("gamepad_thumbstick_l_y");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::RX("gamepad_thumbstick_r_x");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::RY("gamepad_thumbstick_r_y");
|
||||
const AZStd::array<InputChannelId, 4> InputDeviceGamepad::ThumbStickAxis1D::All =
|
||||
{{
|
||||
LX,
|
||||
LY,
|
||||
RX,
|
||||
RY
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickDirection::LU("gamepad_thumbstick_l_up");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickDirection::LD("gamepad_thumbstick_l_down");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickDirection::LL("gamepad_thumbstick_l_left");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickDirection::LR("gamepad_thumbstick_l_right");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickDirection::RU("gamepad_thumbstick_r_up");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickDirection::RD("gamepad_thumbstick_r_down");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickDirection::RL("gamepad_thumbstick_r_left");
|
||||
const InputChannelId InputDeviceGamepad::ThumbStickDirection::RR("gamepad_thumbstick_r_right");
|
||||
const AZStd::array<InputChannelId, 8> InputDeviceGamepad::ThumbStickDirection::All =
|
||||
{{
|
||||
LU,
|
||||
LD,
|
||||
LL,
|
||||
LR,
|
||||
RU,
|
||||
RD,
|
||||
RL,
|
||||
RR
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void InputDeviceGamepad::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
|
||||
@@ -59,75 +59,115 @@ namespace AzFramework
|
||||
//! All the input channel ids that identify game-pad digital button input
|
||||
struct Button
|
||||
{
|
||||
static const InputChannelId A; //!< The bottom diamond face button
|
||||
static const InputChannelId B; //!< The right diamond face button
|
||||
static const InputChannelId X; //!< The left diamond face button
|
||||
static const InputChannelId Y; //!< The top diamond face button
|
||||
static const InputChannelId L1; //!< The top-left shoulder bumper button
|
||||
static const InputChannelId R1; //!< The top-right shoulder bumper button
|
||||
static const InputChannelId L3; //!< The left thumb-stick click button
|
||||
static const InputChannelId R3; //!< The right thumb-stick click button
|
||||
static const InputChannelId DU; //!< The up directional pad button
|
||||
static const InputChannelId DD; //!< The down directional pad button
|
||||
static const InputChannelId DL; //!< The left directional pad button
|
||||
static const InputChannelId DR; //!< The right directional pad button
|
||||
static const InputChannelId Start; //!< The start/pause/options button
|
||||
static const InputChannelId Select; //!< The select/back button
|
||||
static constexpr inline InputChannelId A{"gamepad_button_a"}; //!< The bottom diamond face button
|
||||
static constexpr inline InputChannelId B{"gamepad_button_b"}; //!< The right diamond face button
|
||||
static constexpr inline InputChannelId X{"gamepad_button_x"}; //!< The left diamond face button
|
||||
static constexpr inline InputChannelId Y{"gamepad_button_y"}; //!< The top diamond face button
|
||||
static constexpr inline InputChannelId L1{"gamepad_button_l1"}; //!< The top-left shoulder bumper button
|
||||
static constexpr inline InputChannelId R1{"gamepad_button_r1"}; //!< The top-right shoulder bumper button
|
||||
static constexpr inline InputChannelId L3{"gamepad_button_l3"}; //!< The left thumb-stick click button
|
||||
static constexpr inline InputChannelId R3{"gamepad_button_r3"}; //!< The right thumb-stick click button
|
||||
static constexpr inline InputChannelId DU{"gamepad_button_d_up"}; //!< The up directional pad button
|
||||
static constexpr inline InputChannelId DD{"gamepad_button_d_down"}; //!< The down directional pad button
|
||||
static constexpr inline InputChannelId DL{"gamepad_button_d_left"}; //!< The left directional pad button
|
||||
static constexpr inline InputChannelId DR{"gamepad_button_d_right"}; //!< The right directional pad button
|
||||
static constexpr inline InputChannelId Start{"gamepad_button_start"}; //!< The start/pause/options button
|
||||
static constexpr inline InputChannelId Select{"gamepad_button_select"}; //!< The select/back button
|
||||
|
||||
//!< All digital game-pad button ids
|
||||
static const AZStd::array<InputChannelId, 14> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
L1,
|
||||
R1,
|
||||
L3,
|
||||
R3,
|
||||
DU,
|
||||
DD,
|
||||
DL,
|
||||
DR,
|
||||
Start,
|
||||
Select
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! All the input channel ids that identify game-pad analog trigger input
|
||||
struct Trigger
|
||||
{
|
||||
static const InputChannelId L2; //!< The bottom-left shoulder trigger
|
||||
static const InputChannelId R2; //!< The bottom-right shoulder trigger
|
||||
static constexpr inline InputChannelId L2{"gamepad_trigger_l2"}; //!< The bottom-left shoulder trigger
|
||||
static constexpr inline InputChannelId R2{"gamepad_trigger_r2"}; //!< The bottom-right shoulder trigger
|
||||
|
||||
//!< All analog game-pad trigger ids
|
||||
static const AZStd::array<InputChannelId, 2> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
L2,
|
||||
R2
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! All the input channel ids that identify game-pad thumb-stick 2D axis input
|
||||
struct ThumbStickAxis2D
|
||||
{
|
||||
static const InputChannelId L; //!< The left-hand thumb-stick
|
||||
static const InputChannelId R; //!< The right-hand thumb-stick
|
||||
static constexpr inline InputChannelId L{"gamepad_thumbstick_l"}; //!< The left-hand thumb-stick
|
||||
static constexpr inline InputChannelId R{"gamepad_thumbstick_r"}; //!< The right-hand thumb-stick
|
||||
|
||||
//!< All game-pad thumb-stick 2D axis input channel ids
|
||||
static const AZStd::array<InputChannelId, 2> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
L,
|
||||
R
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! All the input channel ids that identify game-pad thumb-stick 1D axis input
|
||||
struct ThumbStickAxis1D
|
||||
{
|
||||
static const InputChannelId LX; //!< X-axis of the left-hand thumb-stick
|
||||
static const InputChannelId LY; //!< Y-axis of the left-hand thumb-stick
|
||||
static const InputChannelId RX; //!< X-axis of the right-hand thumb-stick
|
||||
static const InputChannelId RY; //!< Y-axis of the right-hand thumb-stick
|
||||
static constexpr inline InputChannelId LX{"gamepad_thumbstick_l_x"}; //!< X-axis of the left-hand thumb-stick
|
||||
static constexpr inline InputChannelId LY{"gamepad_thumbstick_l_y"}; //!< Y-axis of the left-hand thumb-stick
|
||||
static constexpr inline InputChannelId RX{"gamepad_thumbstick_r_x"}; //!< X-axis of the right-hand thumb-stick
|
||||
static constexpr inline InputChannelId RY{"gamepad_thumbstick_r_y"}; //!< Y-axis of the right-hand thumb-stick
|
||||
|
||||
//!< All game-pad thumb-stick 1D axis input channel ids
|
||||
static const AZStd::array<InputChannelId, 4> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
LX,
|
||||
LY,
|
||||
RX,
|
||||
RY
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! All the input channel ids that identify game-pad thumb-stick directional input
|
||||
struct ThumbStickDirection
|
||||
{
|
||||
static const InputChannelId LU; //!< Up on the left-hand thumb-stick
|
||||
static const InputChannelId LD; //!< Down on the left-hand thumb-stick
|
||||
static const InputChannelId LL; //!< Left on the left-hand thumb-stick
|
||||
static const InputChannelId LR; //!< Right on the left-hand thumb-stick
|
||||
static const InputChannelId RU; //!< Up on the left-hand thumb-stick
|
||||
static const InputChannelId RD; //!< Down on the left-hand thumb-stick
|
||||
static const InputChannelId RL; //!< Left on the left-hand thumb-stick
|
||||
static const InputChannelId RR; //!< Right on the left-hand thumb-stick
|
||||
static constexpr inline InputChannelId LU{"gamepad_thumbstick_l_up"}; //!< Up on the left-hand thumb-stick
|
||||
static constexpr inline InputChannelId LD{"gamepad_thumbstick_l_down"}; //!< Down on the left-hand thumb-stick
|
||||
static constexpr inline InputChannelId LL{"gamepad_thumbstick_l_left"}; //!< Left on the left-hand thumb-stick
|
||||
static constexpr inline InputChannelId LR{"gamepad_thumbstick_l_right"}; //!< Right on the left-hand thumb-stick
|
||||
static constexpr inline InputChannelId RU{"gamepad_thumbstick_r_up"}; //!< Up on the left-hand thumb-stick
|
||||
static constexpr inline InputChannelId RD{"gamepad_thumbstick_r_down"}; //!< Down on the left-hand thumb-stick
|
||||
static constexpr inline InputChannelId RL{"gamepad_thumbstick_r_left"}; //!< Left on the left-hand thumb-stick
|
||||
static constexpr inline InputChannelId RR{"gamepad_thumbstick_r_right"}; //!< Right on the left-hand thumb-stick
|
||||
|
||||
//!< All game-pad thumb-stick directional input channel ids
|
||||
static const AZStd::array<InputChannelId, 8> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
LU,
|
||||
LD,
|
||||
LL,
|
||||
LR,
|
||||
RU,
|
||||
RD,
|
||||
RL,
|
||||
RR
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-273
@@ -24,279 +24,6 @@ namespace AzFramework
|
||||
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Alphanumeric Keys
|
||||
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric0("keyboard_key_alphanumeric_0");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric1("keyboard_key_alphanumeric_1");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric2("keyboard_key_alphanumeric_2");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric3("keyboard_key_alphanumeric_3");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric4("keyboard_key_alphanumeric_4");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric5("keyboard_key_alphanumeric_5");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric6("keyboard_key_alphanumeric_6");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric7("keyboard_key_alphanumeric_7");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric8("keyboard_key_alphanumeric_8");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric9("keyboard_key_alphanumeric_9");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericA("keyboard_key_alphanumeric_A");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericB("keyboard_key_alphanumeric_B");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericC("keyboard_key_alphanumeric_C");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericD("keyboard_key_alphanumeric_D");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericE("keyboard_key_alphanumeric_E");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericF("keyboard_key_alphanumeric_F");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericG("keyboard_key_alphanumeric_G");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericH("keyboard_key_alphanumeric_H");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericI("keyboard_key_alphanumeric_I");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericJ("keyboard_key_alphanumeric_J");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericK("keyboard_key_alphanumeric_K");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericL("keyboard_key_alphanumeric_L");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericM("keyboard_key_alphanumeric_M");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericN("keyboard_key_alphanumeric_N");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericO("keyboard_key_alphanumeric_O");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericP("keyboard_key_alphanumeric_P");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericQ("keyboard_key_alphanumeric_Q");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericR("keyboard_key_alphanumeric_R");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericS("keyboard_key_alphanumeric_S");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericT("keyboard_key_alphanumeric_T");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericU("keyboard_key_alphanumeric_U");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericV("keyboard_key_alphanumeric_V");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericW("keyboard_key_alphanumeric_W");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericX("keyboard_key_alphanumeric_X");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericY("keyboard_key_alphanumeric_Y");
|
||||
const InputChannelId InputDeviceKeyboard::Key::AlphanumericZ("keyboard_key_alphanumeric_Z");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Edit (and escape) Keys
|
||||
const InputChannelId InputDeviceKeyboard::Key::EditBackspace("keyboard_key_edit_backspace");
|
||||
const InputChannelId InputDeviceKeyboard::Key::EditCapsLock("keyboard_key_edit_capslock");
|
||||
const InputChannelId InputDeviceKeyboard::Key::EditEnter("keyboard_key_edit_enter");
|
||||
const InputChannelId InputDeviceKeyboard::Key::EditSpace("keyboard_key_edit_space");
|
||||
const InputChannelId InputDeviceKeyboard::Key::EditTab("keyboard_key_edit_tab");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Escape("keyboard_key_escape");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function Keys
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function01("keyboard_key_function_F01");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function02("keyboard_key_function_F02");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function03("keyboard_key_function_F03");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function04("keyboard_key_function_F04");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function05("keyboard_key_function_F05");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function06("keyboard_key_function_F06");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function07("keyboard_key_function_F07");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function08("keyboard_key_function_F08");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function09("keyboard_key_function_F09");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function10("keyboard_key_function_F10");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function11("keyboard_key_function_F11");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function12("keyboard_key_function_F12");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function13("keyboard_key_function_F13");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function14("keyboard_key_function_F14");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function15("keyboard_key_function_F15");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function16("keyboard_key_function_F16");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function17("keyboard_key_function_F17");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function18("keyboard_key_function_F18");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function19("keyboard_key_function_F19");
|
||||
const InputChannelId InputDeviceKeyboard::Key::Function20("keyboard_key_function_F20");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Modifier Keys
|
||||
const InputChannelId InputDeviceKeyboard::Key::ModifierAltL("keyboard_key_modifier_alt_l");
|
||||
const InputChannelId InputDeviceKeyboard::Key::ModifierAltR("keyboard_key_modifier_alt_r");
|
||||
const InputChannelId InputDeviceKeyboard::Key::ModifierCtrlL("keyboard_key_modifier_ctrl_l");
|
||||
const InputChannelId InputDeviceKeyboard::Key::ModifierCtrlR("keyboard_key_modifier_ctrl_r");
|
||||
const InputChannelId InputDeviceKeyboard::Key::ModifierShiftL("keyboard_key_modifier_shift_l");
|
||||
const InputChannelId InputDeviceKeyboard::Key::ModifierShiftR("keyboard_key_modifier_shift_r");
|
||||
const InputChannelId InputDeviceKeyboard::Key::ModifierSuperL("keyboard_key_modifier_super_l");
|
||||
const InputChannelId InputDeviceKeyboard::Key::ModifierSuperR("keyboard_key_modifier_super_r");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Navigation Keys
|
||||
const InputChannelId InputDeviceKeyboard::Key::NavigationArrowDown("keyboard_key_navigation_arrow_down");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NavigationArrowLeft("keyboard_key_navigation_arrow_left");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NavigationArrowRight("keyboard_key_navigation_arrow_right");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NavigationArrowUp("keyboard_key_navigation_arrow_up");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NavigationDelete("keyboard_key_navigation_delete");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NavigationEnd("keyboard_key_navigation_end");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NavigationHome("keyboard_key_navigation_home");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NavigationInsert("keyboard_key_navigation_insert");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NavigationPageDown("keyboard_key_navigation_page_down");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NavigationPageUp("keyboard_key_navigation_page_up");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Numpad Keys
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumLock("keyboard_key_num_lock");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPad0("keyboard_key_numpad_0");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPad1("keyboard_key_numpad_1");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPad2("keyboard_key_numpad_2");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPad3("keyboard_key_numpad_3");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPad4("keyboard_key_numpad_4");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPad5("keyboard_key_numpad_5");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPad6("keyboard_key_numpad_6");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPad7("keyboard_key_numpad_7");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPad8("keyboard_key_numpad_8");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPad9("keyboard_key_numpad_9");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPadAdd("keyboard_key_numpad_add");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPadDecimal("keyboard_key_numpad_decimal");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPadDivide("keyboard_key_numpad_divide");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPadEnter("keyboard_key_numpad_enter");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPadMultiply("keyboard_key_numpad_multiply");
|
||||
const InputChannelId InputDeviceKeyboard::Key::NumPadSubtract("keyboard_key_numpad_subtract");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Punctuation Keys
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationApostrophe("keyboard_key_punctuation_apostrophe");
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationBackslash("keyboard_key_punctuation_backslash");
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationBracketL("keyboard_key_punctuation_bracket_l");
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationBracketR("keyboard_key_punctuation_bracket_r");
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationComma("keyboard_key_punctuation_comma");
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationEquals("keyboard_key_punctuation_equals");
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationHyphen("keyboard_key_punctuation_hyphen");
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationPeriod("keyboard_key_punctuation_period");
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationSemicolon("keyboard_key_punctuation_semicolon");
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationSlash("keyboard_key_punctuation_slash");
|
||||
const InputChannelId InputDeviceKeyboard::Key::PunctuationTilde("keyboard_key_punctuation_tilde");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Supplementary ISO Key
|
||||
const InputChannelId InputDeviceKeyboard::Key::SupplementaryISO("keyboard_key_supplementary_iso");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Windows System Keys
|
||||
const InputChannelId InputDeviceKeyboard::Key::WindowsSystemPause("keyboard_key_windows_system_pause");
|
||||
const InputChannelId InputDeviceKeyboard::Key::WindowsSystemPrint("keyboard_key_windows_system_print");
|
||||
const InputChannelId InputDeviceKeyboard::Key::WindowsSystemScrollLock("keyboard_key_windows_system_scroll_lock");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const AZStd::array<InputChannelId, 112> InputDeviceKeyboard::Key::All =
|
||||
{{
|
||||
// Alphanumeric Keys
|
||||
Alphanumeric0,
|
||||
Alphanumeric1,
|
||||
Alphanumeric2,
|
||||
Alphanumeric3,
|
||||
Alphanumeric4,
|
||||
Alphanumeric5,
|
||||
Alphanumeric6,
|
||||
Alphanumeric7,
|
||||
Alphanumeric8,
|
||||
Alphanumeric9,
|
||||
AlphanumericA,
|
||||
AlphanumericB,
|
||||
AlphanumericC,
|
||||
AlphanumericD,
|
||||
AlphanumericE,
|
||||
AlphanumericF,
|
||||
AlphanumericG,
|
||||
AlphanumericH,
|
||||
AlphanumericI,
|
||||
AlphanumericJ,
|
||||
AlphanumericK,
|
||||
AlphanumericL,
|
||||
AlphanumericM,
|
||||
AlphanumericN,
|
||||
AlphanumericO,
|
||||
AlphanumericP,
|
||||
AlphanumericQ,
|
||||
AlphanumericR,
|
||||
AlphanumericS,
|
||||
AlphanumericT,
|
||||
AlphanumericU,
|
||||
AlphanumericV,
|
||||
AlphanumericW,
|
||||
AlphanumericX,
|
||||
AlphanumericY,
|
||||
AlphanumericZ,
|
||||
|
||||
// Edit (and escape) Keys
|
||||
EditBackspace,
|
||||
EditCapsLock,
|
||||
EditEnter,
|
||||
EditSpace,
|
||||
EditTab,
|
||||
Escape,
|
||||
|
||||
// Function Keys
|
||||
Function01,
|
||||
Function02,
|
||||
Function03,
|
||||
Function04,
|
||||
Function05,
|
||||
Function06,
|
||||
Function07,
|
||||
Function08,
|
||||
Function09,
|
||||
Function10,
|
||||
Function11,
|
||||
Function12,
|
||||
Function13,
|
||||
Function14,
|
||||
Function15,
|
||||
Function16,
|
||||
Function17,
|
||||
Function18,
|
||||
Function19,
|
||||
Function20,
|
||||
|
||||
// Modifier Keys
|
||||
ModifierAltL,
|
||||
ModifierAltR,
|
||||
ModifierCtrlL,
|
||||
ModifierCtrlR,
|
||||
ModifierShiftL,
|
||||
ModifierShiftR,
|
||||
ModifierSuperL,
|
||||
ModifierSuperR,
|
||||
|
||||
// Navigation Keys
|
||||
NavigationArrowDown,
|
||||
NavigationArrowLeft,
|
||||
NavigationArrowRight,
|
||||
NavigationArrowUp,
|
||||
NavigationDelete,
|
||||
NavigationEnd,
|
||||
NavigationHome,
|
||||
NavigationInsert,
|
||||
NavigationPageDown,
|
||||
NavigationPageUp,
|
||||
|
||||
// Numpad Keys
|
||||
NumLock,
|
||||
NumPad0,
|
||||
NumPad1,
|
||||
NumPad2,
|
||||
NumPad3,
|
||||
NumPad4,
|
||||
NumPad5,
|
||||
NumPad6,
|
||||
NumPad7,
|
||||
NumPad8,
|
||||
NumPad9,
|
||||
NumPadAdd,
|
||||
NumPadDecimal,
|
||||
NumPadDivide,
|
||||
NumPadEnter,
|
||||
NumPadMultiply,
|
||||
NumPadSubtract,
|
||||
|
||||
// Punctuation Keys
|
||||
PunctuationApostrophe,
|
||||
PunctuationBackslash,
|
||||
PunctuationBracketL,
|
||||
PunctuationBracketR,
|
||||
PunctuationComma,
|
||||
PunctuationEquals,
|
||||
PunctuationHyphen,
|
||||
PunctuationPeriod,
|
||||
PunctuationSemicolon,
|
||||
PunctuationSlash,
|
||||
PunctuationTilde,
|
||||
|
||||
// Supplementary ISO Key
|
||||
SupplementaryISO,
|
||||
|
||||
// Windows System Keys
|
||||
WindowsSystemPause,
|
||||
WindowsSystemPrint,
|
||||
WindowsSystemScrollLock
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ModifierKeyMask GetCorrespondingModifierKeyMask(const InputChannelId& channelId)
|
||||
{
|
||||
|
||||
+245
-114
@@ -94,137 +94,268 @@ namespace AzFramework
|
||||
struct Key
|
||||
{
|
||||
// Alphanumeric Keys
|
||||
static const InputChannelId Alphanumeric0; //!< The 0 key
|
||||
static const InputChannelId Alphanumeric1; //!< The 1 key
|
||||
static const InputChannelId Alphanumeric2; //!< The 2 key
|
||||
static const InputChannelId Alphanumeric3; //!< The 3 key
|
||||
static const InputChannelId Alphanumeric4; //!< The 4 key
|
||||
static const InputChannelId Alphanumeric5; //!< The 5 key
|
||||
static const InputChannelId Alphanumeric6; //!< The 6 key
|
||||
static const InputChannelId Alphanumeric7; //!< The 7 key
|
||||
static const InputChannelId Alphanumeric8; //!< The 8 key
|
||||
static const InputChannelId Alphanumeric9; //!< The 9 key
|
||||
static const InputChannelId AlphanumericA; //!< The A key
|
||||
static const InputChannelId AlphanumericB; //!< The B key
|
||||
static const InputChannelId AlphanumericC; //!< The C key
|
||||
static const InputChannelId AlphanumericD; //!< The D key
|
||||
static const InputChannelId AlphanumericE; //!< The E key
|
||||
static const InputChannelId AlphanumericF; //!< The F key
|
||||
static const InputChannelId AlphanumericG; //!< The G key
|
||||
static const InputChannelId AlphanumericH; //!< The H key
|
||||
static const InputChannelId AlphanumericI; //!< The I key
|
||||
static const InputChannelId AlphanumericJ; //!< The J key
|
||||
static const InputChannelId AlphanumericK; //!< The K key
|
||||
static const InputChannelId AlphanumericL; //!< The L key
|
||||
static const InputChannelId AlphanumericM; //!< The M key
|
||||
static const InputChannelId AlphanumericN; //!< The N key
|
||||
static const InputChannelId AlphanumericO; //!< The O key
|
||||
static const InputChannelId AlphanumericP; //!< The P key
|
||||
static const InputChannelId AlphanumericQ; //!< The Q key
|
||||
static const InputChannelId AlphanumericR; //!< The R key
|
||||
static const InputChannelId AlphanumericS; //!< The S key
|
||||
static const InputChannelId AlphanumericT; //!< The T key
|
||||
static const InputChannelId AlphanumericU; //!< The U key
|
||||
static const InputChannelId AlphanumericV; //!< The V key
|
||||
static const InputChannelId AlphanumericW; //!< The W key
|
||||
static const InputChannelId AlphanumericX; //!< The X key
|
||||
static const InputChannelId AlphanumericY; //!< The Y key
|
||||
static const InputChannelId AlphanumericZ; //!< The Z key
|
||||
static constexpr inline InputChannelId Alphanumeric0{"keyboard_key_alphanumeric_0"}; //!< The 0 key
|
||||
static constexpr inline InputChannelId Alphanumeric1{"keyboard_key_alphanumeric_1"}; //!< The 1 key
|
||||
static constexpr inline InputChannelId Alphanumeric2{"keyboard_key_alphanumeric_2"}; //!< The 2 key
|
||||
static constexpr inline InputChannelId Alphanumeric3{"keyboard_key_alphanumeric_3"}; //!< The 3 key
|
||||
static constexpr inline InputChannelId Alphanumeric4{"keyboard_key_alphanumeric_4"}; //!< The 4 key
|
||||
static constexpr inline InputChannelId Alphanumeric5{"keyboard_key_alphanumeric_5"}; //!< The 5 key
|
||||
static constexpr inline InputChannelId Alphanumeric6{"keyboard_key_alphanumeric_6"}; //!< The 6 key
|
||||
static constexpr inline InputChannelId Alphanumeric7{"keyboard_key_alphanumeric_7"}; //!< The 7 key
|
||||
static constexpr inline InputChannelId Alphanumeric8{"keyboard_key_alphanumeric_8"}; //!< The 8 key
|
||||
static constexpr inline InputChannelId Alphanumeric9{"keyboard_key_alphanumeric_9"}; //!< The 9 key
|
||||
static constexpr inline InputChannelId AlphanumericA{"keyboard_key_alphanumeric_A"}; //!< The A key
|
||||
static constexpr inline InputChannelId AlphanumericB{"keyboard_key_alphanumeric_B"}; //!< The B key
|
||||
static constexpr inline InputChannelId AlphanumericC{"keyboard_key_alphanumeric_C"}; //!< The C key
|
||||
static constexpr inline InputChannelId AlphanumericD{"keyboard_key_alphanumeric_D"}; //!< The D key
|
||||
static constexpr inline InputChannelId AlphanumericE{"keyboard_key_alphanumeric_E"}; //!< The E key
|
||||
static constexpr inline InputChannelId AlphanumericF{"keyboard_key_alphanumeric_F"}; //!< The F key
|
||||
static constexpr inline InputChannelId AlphanumericG{"keyboard_key_alphanumeric_G"}; //!< The G key
|
||||
static constexpr inline InputChannelId AlphanumericH{"keyboard_key_alphanumeric_H"}; //!< The H key
|
||||
static constexpr inline InputChannelId AlphanumericI{"keyboard_key_alphanumeric_I"}; //!< The I key
|
||||
static constexpr inline InputChannelId AlphanumericJ{"keyboard_key_alphanumeric_J"}; //!< The J key
|
||||
static constexpr inline InputChannelId AlphanumericK{"keyboard_key_alphanumeric_K"}; //!< The K key
|
||||
static constexpr inline InputChannelId AlphanumericL{"keyboard_key_alphanumeric_L"}; //!< The L key
|
||||
static constexpr inline InputChannelId AlphanumericM{"keyboard_key_alphanumeric_M"}; //!< The M key
|
||||
static constexpr inline InputChannelId AlphanumericN{"keyboard_key_alphanumeric_N"}; //!< The N key
|
||||
static constexpr inline InputChannelId AlphanumericO{"keyboard_key_alphanumeric_O"}; //!< The O key
|
||||
static constexpr inline InputChannelId AlphanumericP{"keyboard_key_alphanumeric_P"}; //!< The P key
|
||||
static constexpr inline InputChannelId AlphanumericQ{"keyboard_key_alphanumeric_Q"}; //!< The Q key
|
||||
static constexpr inline InputChannelId AlphanumericR{"keyboard_key_alphanumeric_R"}; //!< The R key
|
||||
static constexpr inline InputChannelId AlphanumericS{"keyboard_key_alphanumeric_S"}; //!< The S key
|
||||
static constexpr inline InputChannelId AlphanumericT{"keyboard_key_alphanumeric_T"}; //!< The T key
|
||||
static constexpr inline InputChannelId AlphanumericU{"keyboard_key_alphanumeric_U"}; //!< The U key
|
||||
static constexpr inline InputChannelId AlphanumericV{"keyboard_key_alphanumeric_V"}; //!< The V key
|
||||
static constexpr inline InputChannelId AlphanumericW{"keyboard_key_alphanumeric_W"}; //!< The W key
|
||||
static constexpr inline InputChannelId AlphanumericX{"keyboard_key_alphanumeric_X"}; //!< The X key
|
||||
static constexpr inline InputChannelId AlphanumericY{"keyboard_key_alphanumeric_Y"}; //!< The Y key
|
||||
static constexpr inline InputChannelId AlphanumericZ{"keyboard_key_alphanumeric_Z"}; //!< The Z key
|
||||
|
||||
// Edit (and escape) Keys
|
||||
static const InputChannelId EditBackspace; //!< The backspace key
|
||||
static const InputChannelId EditCapsLock; //!< The caps lock key
|
||||
static const InputChannelId EditEnter; //!< The enter/return key
|
||||
static const InputChannelId EditSpace; //!< The spacebar key
|
||||
static const InputChannelId EditTab; //!< The tab key
|
||||
static const InputChannelId Escape; //!< The escape key
|
||||
// Edit {and escape} Keys
|
||||
static constexpr inline InputChannelId EditBackspace{"keyboard_key_edit_backspace"}; //!< The backspace key
|
||||
static constexpr inline InputChannelId EditCapsLock{"keyboard_key_edit_capslock"}; //!< The caps lock key
|
||||
static constexpr inline InputChannelId EditEnter{"keyboard_key_edit_enter"}; //!< The enter/return key
|
||||
static constexpr inline InputChannelId EditSpace{"keyboard_key_edit_space"}; //!< The spacebar key
|
||||
static constexpr inline InputChannelId EditTab{"keyboard_key_edit_tab"}; //!< The tab key
|
||||
static constexpr inline InputChannelId Escape{"keyboard_key_escape"}; //!< The escape key
|
||||
|
||||
// Function Keys
|
||||
static const InputChannelId Function01; //!< The F1 key
|
||||
static const InputChannelId Function02; //!< The F2 key
|
||||
static const InputChannelId Function03; //!< The F3 key
|
||||
static const InputChannelId Function04; //!< The F4 key
|
||||
static const InputChannelId Function05; //!< The F5 key
|
||||
static const InputChannelId Function06; //!< The F6 key
|
||||
static const InputChannelId Function07; //!< The F7 key
|
||||
static const InputChannelId Function08; //!< The F8 key
|
||||
static const InputChannelId Function09; //!< The F9 key
|
||||
static const InputChannelId Function10; //!< The F10 key
|
||||
static const InputChannelId Function11; //!< The F11 key
|
||||
static const InputChannelId Function12; //!< The F12 key
|
||||
static const InputChannelId Function13; //!< The F13 key
|
||||
static const InputChannelId Function14; //!< The F14 key
|
||||
static const InputChannelId Function15; //!< The F15 key
|
||||
static const InputChannelId Function16; //!< The F16 key
|
||||
static const InputChannelId Function17; //!< The F17 key
|
||||
static const InputChannelId Function18; //!< The F18 key
|
||||
static const InputChannelId Function19; //!< The F19 key
|
||||
static const InputChannelId Function20; //!< The F20 key
|
||||
static constexpr inline InputChannelId Function01{"keyboard_key_function_F01"}; //!< The F1 key
|
||||
static constexpr inline InputChannelId Function02{"keyboard_key_function_F02"}; //!< The F2 key
|
||||
static constexpr inline InputChannelId Function03{"keyboard_key_function_F03"}; //!< The F3 key
|
||||
static constexpr inline InputChannelId Function04{"keyboard_key_function_F04"}; //!< The F4 key
|
||||
static constexpr inline InputChannelId Function05{"keyboard_key_function_F05"}; //!< The F5 key
|
||||
static constexpr inline InputChannelId Function06{"keyboard_key_function_F06"}; //!< The F6 key
|
||||
static constexpr inline InputChannelId Function07{"keyboard_key_function_F07"}; //!< The F7 key
|
||||
static constexpr inline InputChannelId Function08{"keyboard_key_function_F08"}; //!< The F8 key
|
||||
static constexpr inline InputChannelId Function09{"keyboard_key_function_F09"}; //!< The F9 key
|
||||
static constexpr inline InputChannelId Function10{"keyboard_key_function_F10"}; //!< The F10 key
|
||||
static constexpr inline InputChannelId Function11{"keyboard_key_function_F11"}; //!< The F11 key
|
||||
static constexpr inline InputChannelId Function12{"keyboard_key_function_F12"}; //!< The F12 key
|
||||
static constexpr inline InputChannelId Function13{"keyboard_key_function_F13"}; //!< The F13 key
|
||||
static constexpr inline InputChannelId Function14{"keyboard_key_function_F14"}; //!< The F14 key
|
||||
static constexpr inline InputChannelId Function15{"keyboard_key_function_F15"}; //!< The F15 key
|
||||
static constexpr inline InputChannelId Function16{"keyboard_key_function_F16"}; //!< The F16 key
|
||||
static constexpr inline InputChannelId Function17{"keyboard_key_function_F17"}; //!< The F17 key
|
||||
static constexpr inline InputChannelId Function18{"keyboard_key_function_F18"}; //!< The F18 key
|
||||
static constexpr inline InputChannelId Function19{"keyboard_key_function_F19"}; //!< The F19 key
|
||||
static constexpr inline InputChannelId Function20{"keyboard_key_function_F20"}; //!< The F20 key
|
||||
|
||||
// Modifier Keys
|
||||
static const InputChannelId ModifierAltL; //!< The left alt/option key
|
||||
static const InputChannelId ModifierAltR; //!< The right alt/option key
|
||||
static const InputChannelId ModifierCtrlL; //!< The left control key
|
||||
static const InputChannelId ModifierCtrlR; //!< The right control key
|
||||
static const InputChannelId ModifierShiftL; //!< The left shift key
|
||||
static const InputChannelId ModifierShiftR; //!< The right shift key
|
||||
static const InputChannelId ModifierSuperL; //!< The left super (windows or apple) key
|
||||
static const InputChannelId ModifierSuperR; //!< The right super (windows or apple) key
|
||||
static constexpr inline InputChannelId ModifierAltL{"keyboard_key_modifier_alt_l"}; //!< The left alt/option key
|
||||
static constexpr inline InputChannelId ModifierAltR{"keyboard_key_modifier_alt_r"}; //!< The right alt/option key
|
||||
static constexpr inline InputChannelId ModifierCtrlL{"keyboard_key_modifier_ctrl_l"}; //!< The left control key
|
||||
static constexpr inline InputChannelId ModifierCtrlR{"keyboard_key_modifier_ctrl_r"}; //!< The right control key
|
||||
static constexpr inline InputChannelId ModifierShiftL{"keyboard_key_modifier_shift_l"}; //!< The left shift key
|
||||
static constexpr inline InputChannelId ModifierShiftR{"keyboard_key_modifier_shift_r"}; //!< The right shift key
|
||||
static constexpr inline InputChannelId ModifierSuperL{"keyboard_key_modifier_super_l"}; //!< The left super {windows or apple} key
|
||||
static constexpr inline InputChannelId ModifierSuperR{"keyboard_key_modifier_super_r"}; //!< The right super {windows or apple} key
|
||||
|
||||
// Navigation Keys
|
||||
static const InputChannelId NavigationArrowDown; //!< The down arrow key
|
||||
static const InputChannelId NavigationArrowLeft; //!< The left arrow key
|
||||
static const InputChannelId NavigationArrowRight; //!< The right arrow key
|
||||
static const InputChannelId NavigationArrowUp; //!< The up arrow key
|
||||
static const InputChannelId NavigationDelete; //!< The delete key
|
||||
static const InputChannelId NavigationEnd; //!< The end key
|
||||
static const InputChannelId NavigationHome; //!< The home key
|
||||
static const InputChannelId NavigationInsert; //!< The insert key
|
||||
static const InputChannelId NavigationPageDown; //!< The page down key
|
||||
static const InputChannelId NavigationPageUp; //!< The page up key
|
||||
static constexpr inline InputChannelId NavigationArrowDown{"keyboard_key_navigation_arrow_down"}; //!< The down arrow key
|
||||
static constexpr inline InputChannelId NavigationArrowLeft{"keyboard_key_navigation_arrow_left"}; //!< The left arrow key
|
||||
static constexpr inline InputChannelId NavigationArrowRight{"keyboard_key_navigation_arrow_right"}; //!< The right arrow key
|
||||
static constexpr inline InputChannelId NavigationArrowUp{"keyboard_key_navigation_arrow_up"}; //!< The up arrow key
|
||||
static constexpr inline InputChannelId NavigationDelete{"keyboard_key_navigation_delete"}; //!< The delete key
|
||||
static constexpr inline InputChannelId NavigationEnd{"keyboard_key_navigation_end"}; //!< The end key
|
||||
static constexpr inline InputChannelId NavigationHome{"keyboard_key_navigation_home"}; //!< The home key
|
||||
static constexpr inline InputChannelId NavigationInsert{"keyboard_key_navigation_insert"}; //!< The insert key
|
||||
static constexpr inline InputChannelId NavigationPageDown{"keyboard_key_navigation_page_down"}; //!< The page down key
|
||||
static constexpr inline InputChannelId NavigationPageUp{"keyboard_key_navigation_page_up"}; //!< The page up key
|
||||
|
||||
// Numpad Keys
|
||||
static const InputChannelId NumLock; //!< The num lock key (the clear key on apple keyboards)
|
||||
static const InputChannelId NumPad0; //!< The numpad 0 key
|
||||
static const InputChannelId NumPad1; //!< The numpad 1 key
|
||||
static const InputChannelId NumPad2; //!< The numpad 2 key
|
||||
static const InputChannelId NumPad3; //!< The numpad 3 key
|
||||
static const InputChannelId NumPad4; //!< The numpad 4 key
|
||||
static const InputChannelId NumPad5; //!< The numpad 5 key
|
||||
static const InputChannelId NumPad6; //!< The numpad 6 key
|
||||
static const InputChannelId NumPad7; //!< The numpad 7 key
|
||||
static const InputChannelId NumPad8; //!< The numpad 8 key
|
||||
static const InputChannelId NumPad9; //!< The numpad 9 key
|
||||
static const InputChannelId NumPadAdd; //!< The numpad add key
|
||||
static const InputChannelId NumPadDecimal; //!< The numpad decimal key
|
||||
static const InputChannelId NumPadDivide; //!< The numpad divide key
|
||||
static const InputChannelId NumPadEnter; //!< The numpad enter key
|
||||
static const InputChannelId NumPadMultiply; //!< The numpad multiply key
|
||||
static const InputChannelId NumPadSubtract; //!< The numpad subtract key
|
||||
static constexpr inline InputChannelId NumLock{"keyboard_key_num_lock"}; //!< The num lock key {the clear key on apple keyboards}
|
||||
static constexpr inline InputChannelId NumPad0{"keyboard_key_numpad_0"}; //!< The numpad 0 key
|
||||
static constexpr inline InputChannelId NumPad1{"keyboard_key_numpad_1"}; //!< The numpad 1 key
|
||||
static constexpr inline InputChannelId NumPad2{"keyboard_key_numpad_2"}; //!< The numpad 2 key
|
||||
static constexpr inline InputChannelId NumPad3{"keyboard_key_numpad_3"}; //!< The numpad 3 key
|
||||
static constexpr inline InputChannelId NumPad4{"keyboard_key_numpad_4"}; //!< The numpad 4 key
|
||||
static constexpr inline InputChannelId NumPad5{"keyboard_key_numpad_5"}; //!< The numpad 5 key
|
||||
static constexpr inline InputChannelId NumPad6{"keyboard_key_numpad_6"}; //!< The numpad 6 key
|
||||
static constexpr inline InputChannelId NumPad7{"keyboard_key_numpad_7"}; //!< The numpad 7 key
|
||||
static constexpr inline InputChannelId NumPad8{"keyboard_key_numpad_8"}; //!< The numpad 8 key
|
||||
static constexpr inline InputChannelId NumPad9{"keyboard_key_numpad_9"}; //!< The numpad 9 key
|
||||
static constexpr inline InputChannelId NumPadAdd{"keyboard_key_numpad_add"}; //!< The numpad add key
|
||||
static constexpr inline InputChannelId NumPadDecimal{"keyboard_key_numpad_decimal"}; //!< The numpad decimal key
|
||||
static constexpr inline InputChannelId NumPadDivide{"keyboard_key_numpad_divide"}; //!< The numpad divide key
|
||||
static constexpr inline InputChannelId NumPadEnter{"keyboard_key_numpad_enter"}; //!< The numpad enter key
|
||||
static constexpr inline InputChannelId NumPadMultiply{"keyboard_key_numpad_multiply"}; //!< The numpad multiply key
|
||||
static constexpr inline InputChannelId NumPadSubtract{"keyboard_key_numpad_subtract"}; //!< The numpad subtract key
|
||||
|
||||
// Punctuation Keys
|
||||
static const InputChannelId PunctuationApostrophe; //!< The apostrophe key
|
||||
static const InputChannelId PunctuationBackslash; //!< The backslash key
|
||||
static const InputChannelId PunctuationBracketL; //!< The left bracket key
|
||||
static const InputChannelId PunctuationBracketR; //!< The right bracket key
|
||||
static const InputChannelId PunctuationComma; //!< The comma key
|
||||
static const InputChannelId PunctuationEquals; //!< The equals key
|
||||
static const InputChannelId PunctuationHyphen; //!< The hyphen/underscore key
|
||||
static const InputChannelId PunctuationPeriod; //!< The period key
|
||||
static const InputChannelId PunctuationSemicolon; //!< The semicolon key
|
||||
static const InputChannelId PunctuationSlash; //!< The (forward) slash key
|
||||
static const InputChannelId PunctuationTilde; //!< The tilde/grave key
|
||||
static constexpr inline InputChannelId PunctuationApostrophe{"keyboard_key_punctuation_apostrophe"}; //!< The apostrophe key
|
||||
static constexpr inline InputChannelId PunctuationBackslash{"keyboard_key_punctuation_backslash"}; //!< The backslash key
|
||||
static constexpr inline InputChannelId PunctuationBracketL{"keyboard_key_punctuation_bracket_l"}; //!< The left bracket key
|
||||
static constexpr inline InputChannelId PunctuationBracketR{"keyboard_key_punctuation_bracket_r"}; //!< The right bracket key
|
||||
static constexpr inline InputChannelId PunctuationComma{"keyboard_key_punctuation_comma"}; //!< The comma key
|
||||
static constexpr inline InputChannelId PunctuationEquals{"keyboard_key_punctuation_equals"}; //!< The equals key
|
||||
static constexpr inline InputChannelId PunctuationHyphen{"keyboard_key_punctuation_hyphen"}; //!< The hyphen/underscore key
|
||||
static constexpr inline InputChannelId PunctuationPeriod{"keyboard_key_punctuation_period"}; //!< The period key
|
||||
static constexpr inline InputChannelId PunctuationSemicolon{"keyboard_key_punctuation_semicolon"}; //!< The semicolon key
|
||||
static constexpr inline InputChannelId PunctuationSlash{"keyboard_key_punctuation_slash"}; //!< The {forward} slash key
|
||||
static constexpr inline InputChannelId PunctuationTilde{"keyboard_key_punctuation_tilde"}; //!< The tilde/grave key
|
||||
|
||||
// Supplementary ISO Key
|
||||
static const InputChannelId SupplementaryISO; //!< The supplementary ISO layout key
|
||||
static constexpr inline InputChannelId SupplementaryISO{"keyboard_key_supplementary_iso"}; //!< The supplementary ISO layout key
|
||||
|
||||
// Windows System Keys
|
||||
static const InputChannelId WindowsSystemPause; //!< The windows pause key
|
||||
static const InputChannelId WindowsSystemPrint; //!< The windows print key
|
||||
static const InputChannelId WindowsSystemScrollLock; //!< The windows scroll lock key
|
||||
static constexpr inline InputChannelId WindowsSystemPause{"keyboard_key_windows_system_pause"}; //!< The windows pause key
|
||||
static constexpr inline InputChannelId WindowsSystemPrint{"keyboard_key_windows_system_print"}; //!< The windows print key
|
||||
static constexpr inline InputChannelId WindowsSystemScrollLock{"keyboard_key_windows_system_scroll_lock"}; //!< The windows scroll lock key
|
||||
|
||||
//!< All keyboard key ids
|
||||
static const AZStd::array<InputChannelId, 112> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
// Alphanumeric Keys
|
||||
Alphanumeric0,
|
||||
Alphanumeric1,
|
||||
Alphanumeric2,
|
||||
Alphanumeric3,
|
||||
Alphanumeric4,
|
||||
Alphanumeric5,
|
||||
Alphanumeric6,
|
||||
Alphanumeric7,
|
||||
Alphanumeric8,
|
||||
Alphanumeric9,
|
||||
AlphanumericA,
|
||||
AlphanumericB,
|
||||
AlphanumericC,
|
||||
AlphanumericD,
|
||||
AlphanumericE,
|
||||
AlphanumericF,
|
||||
AlphanumericG,
|
||||
AlphanumericH,
|
||||
AlphanumericI,
|
||||
AlphanumericJ,
|
||||
AlphanumericK,
|
||||
AlphanumericL,
|
||||
AlphanumericM,
|
||||
AlphanumericN,
|
||||
AlphanumericO,
|
||||
AlphanumericP,
|
||||
AlphanumericQ,
|
||||
AlphanumericR,
|
||||
AlphanumericS,
|
||||
AlphanumericT,
|
||||
AlphanumericU,
|
||||
AlphanumericV,
|
||||
AlphanumericW,
|
||||
AlphanumericX,
|
||||
AlphanumericY,
|
||||
AlphanumericZ,
|
||||
|
||||
// Edit (and escape) Keys
|
||||
EditBackspace,
|
||||
EditCapsLock,
|
||||
EditEnter,
|
||||
EditSpace,
|
||||
EditTab,
|
||||
Escape,
|
||||
|
||||
// Function Keys
|
||||
Function01,
|
||||
Function02,
|
||||
Function03,
|
||||
Function04,
|
||||
Function05,
|
||||
Function06,
|
||||
Function07,
|
||||
Function08,
|
||||
Function09,
|
||||
Function10,
|
||||
Function11,
|
||||
Function12,
|
||||
Function13,
|
||||
Function14,
|
||||
Function15,
|
||||
Function16,
|
||||
Function17,
|
||||
Function18,
|
||||
Function19,
|
||||
Function20,
|
||||
|
||||
// Modifier Keys
|
||||
ModifierAltL,
|
||||
ModifierAltR,
|
||||
ModifierCtrlL,
|
||||
ModifierCtrlR,
|
||||
ModifierShiftL,
|
||||
ModifierShiftR,
|
||||
ModifierSuperL,
|
||||
ModifierSuperR,
|
||||
|
||||
// Navigation Keys
|
||||
NavigationArrowDown,
|
||||
NavigationArrowLeft,
|
||||
NavigationArrowRight,
|
||||
NavigationArrowUp,
|
||||
NavigationDelete,
|
||||
NavigationEnd,
|
||||
NavigationHome,
|
||||
NavigationInsert,
|
||||
NavigationPageDown,
|
||||
NavigationPageUp,
|
||||
|
||||
// Numpad Keys
|
||||
NumLock,
|
||||
NumPad0,
|
||||
NumPad1,
|
||||
NumPad2,
|
||||
NumPad3,
|
||||
NumPad4,
|
||||
NumPad5,
|
||||
NumPad6,
|
||||
NumPad7,
|
||||
NumPad8,
|
||||
NumPad9,
|
||||
NumPadAdd,
|
||||
NumPadDecimal,
|
||||
NumPadDivide,
|
||||
NumPadEnter,
|
||||
NumPadMultiply,
|
||||
NumPadSubtract,
|
||||
|
||||
// Punctuation Keys
|
||||
PunctuationApostrophe,
|
||||
PunctuationBackslash,
|
||||
PunctuationBracketL,
|
||||
PunctuationBracketR,
|
||||
PunctuationComma,
|
||||
PunctuationEquals,
|
||||
PunctuationHyphen,
|
||||
PunctuationPeriod,
|
||||
PunctuationSemicolon,
|
||||
PunctuationSlash,
|
||||
PunctuationTilde,
|
||||
|
||||
// Supplementary ISO Key
|
||||
SupplementaryISO,
|
||||
|
||||
// Windows System Keys
|
||||
WindowsSystemPause,
|
||||
WindowsSystemPrint,
|
||||
WindowsSystemScrollLock
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -23,44 +23,6 @@ namespace AzFramework
|
||||
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceMotion::Acceleration::Gravity("motion_acceleration_gravity");
|
||||
const InputChannelId InputDeviceMotion::Acceleration::Raw("motion_acceleration_raw");
|
||||
const InputChannelId InputDeviceMotion::Acceleration::User("motion_acceleration_user");
|
||||
const AZStd::array<InputChannelId, 3> InputDeviceMotion::Acceleration::All =
|
||||
{{
|
||||
Gravity,
|
||||
Raw,
|
||||
User
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceMotion::RotationRate::Raw("motion_rotation_rate_raw");
|
||||
const InputChannelId InputDeviceMotion::RotationRate::Unbiased("motion_rotation_rate_unbiased");
|
||||
const AZStd::array<InputChannelId, 2> InputDeviceMotion::RotationRate::All =
|
||||
{{
|
||||
Raw,
|
||||
Unbiased
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceMotion::MagneticField::North("motion_magnetic_field_north");
|
||||
const InputChannelId InputDeviceMotion::MagneticField::Raw("motion_magnetic_field_raw");
|
||||
const InputChannelId InputDeviceMotion::MagneticField::Unbiased("motion_magnetic_field_unbiased");
|
||||
const AZStd::array<InputChannelId, 3> InputDeviceMotion::MagneticField::All =
|
||||
{{
|
||||
North,
|
||||
Raw,
|
||||
Unbiased
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceMotion::Orientation::Current("motion_orientation_current");
|
||||
const AZStd::array<InputChannelId, 1> InputDeviceMotion::Orientation::All =
|
||||
{{
|
||||
Current
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void InputDeviceMotion::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
|
||||
@@ -44,12 +44,17 @@ namespace AzFramework
|
||||
//! - InputMotionSensorRequests::SetInputChannelEnabled
|
||||
struct Acceleration
|
||||
{
|
||||
static const InputChannelId Gravity;
|
||||
static const InputChannelId Raw;
|
||||
static const InputChannelId User;
|
||||
static constexpr inline InputChannelId Gravity{"motion_acceleration_gravity"};
|
||||
static constexpr inline InputChannelId Raw{"motion_acceleration_raw"};
|
||||
static constexpr inline InputChannelId User{"motion_acceleration_user"};
|
||||
|
||||
//!< All acceleration input channel ids
|
||||
static const AZStd::array<InputChannelId, 3> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
Gravity,
|
||||
Raw,
|
||||
User
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -60,11 +65,15 @@ namespace AzFramework
|
||||
//! - InputMotionSensorRequests::SetInputChannelEnabled
|
||||
struct RotationRate
|
||||
{
|
||||
static const InputChannelId Raw;
|
||||
static const InputChannelId Unbiased;
|
||||
static constexpr inline InputChannelId Raw{"motion_rotation_rate_raw"};
|
||||
static constexpr inline InputChannelId Unbiased{"motion_rotation_rate_unbiased"};
|
||||
|
||||
//!< All rotation rate input channel ids
|
||||
static const AZStd::array<InputChannelId, 2> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
Raw,
|
||||
Unbiased
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -75,12 +84,17 @@ namespace AzFramework
|
||||
//! - InputMotionSensorRequests::SetInputChannelEnabled
|
||||
struct MagneticField
|
||||
{
|
||||
static const InputChannelId North;
|
||||
static const InputChannelId Raw;
|
||||
static const InputChannelId Unbiased;
|
||||
static constexpr inline InputChannelId North{"motion_magnetic_field_north"};
|
||||
static constexpr inline InputChannelId Raw{"motion_magnetic_field_raw"};
|
||||
static constexpr inline InputChannelId Unbiased{"motion_magnetic_field_unbiased"};
|
||||
|
||||
//!< All magnetic field input channel ids
|
||||
static const AZStd::array<InputChannelId, 3> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
North,
|
||||
Raw,
|
||||
Unbiased
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -91,10 +105,13 @@ namespace AzFramework
|
||||
//! - InputMotionSensorRequests::SetInputChannelEnabled
|
||||
struct Orientation
|
||||
{
|
||||
static const InputChannelId Current;
|
||||
static constexpr inline InputChannelId Current{"motion_orientation_current"};
|
||||
|
||||
//!< All orientation input channel ids
|
||||
static const AZStd::array<InputChannelId, 1> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
Current
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -33,35 +33,6 @@ namespace AzFramework
|
||||
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceMouse::Button::Left("mouse_button_left");
|
||||
const InputChannelId InputDeviceMouse::Button::Right("mouse_button_right");
|
||||
const InputChannelId InputDeviceMouse::Button::Middle("mouse_button_middle");
|
||||
const InputChannelId InputDeviceMouse::Button::Other1("mouse_button_other1");
|
||||
const InputChannelId InputDeviceMouse::Button::Other2("mouse_button_other2");
|
||||
const AZStd::array<InputChannelId, 5> InputDeviceMouse::Button::All =
|
||||
{{
|
||||
Left,
|
||||
Right,
|
||||
Middle,
|
||||
Other1,
|
||||
Other2
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceMouse::Movement::X("mouse_delta_x");
|
||||
const InputChannelId InputDeviceMouse::Movement::Y("mouse_delta_y");
|
||||
const InputChannelId InputDeviceMouse::Movement::Z("mouse_delta_z");
|
||||
const AZStd::array<InputChannelId, 3> InputDeviceMouse::Movement::All =
|
||||
{{
|
||||
X,
|
||||
Y,
|
||||
Z
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceMouse::SystemCursorPosition("mouse_system_cursor_position");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void InputDeviceMouse::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
|
||||
@@ -66,14 +66,21 @@ namespace AzFramework
|
||||
//! been implemented for windows simply to provide for backwards compatibility with CryInput.
|
||||
struct Button
|
||||
{
|
||||
static const InputChannelId Left; //!< The left mouse button
|
||||
static const InputChannelId Right; //!< The right mouse button
|
||||
static const InputChannelId Middle; //!< The middle mouse button
|
||||
static const InputChannelId Other1; //!< DEPRECATED: the x1 mouse button
|
||||
static const InputChannelId Other2; //!< DEPRECATED: the x2 mouse button
|
||||
static constexpr inline InputChannelId Left{"mouse_button_left"}; //!< The left mouse button
|
||||
static constexpr inline InputChannelId Right{"mouse_button_right"}; //!< The right mouse button
|
||||
static constexpr inline InputChannelId Middle{"mouse_button_middle"}; //!< The middle mouse button
|
||||
static constexpr inline InputChannelId Other1{"mouse_button_other1"}; //!< DEPRECATED: the x1 mouse button
|
||||
static constexpr inline InputChannelId Other2{"mouse_button_other2"}; //!< DEPRECATED: the x2 mouse button
|
||||
|
||||
//!< All mouse button ids
|
||||
static const AZStd::array<InputChannelId, 5> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
Left,
|
||||
Right,
|
||||
Middle,
|
||||
Other1,
|
||||
Other2
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -82,12 +89,17 @@ namespace AzFramework
|
||||
//! directly correlate to the mouse position (which is queried directly from the system).
|
||||
struct Movement
|
||||
{
|
||||
static const InputChannelId X; //!< Raw horizontal mouse movement over the last frame
|
||||
static const InputChannelId Y; //!< Raw vertical mouse movement over the last frame
|
||||
static const InputChannelId Z; //!< Raw mouse wheel movement over the last frame
|
||||
static constexpr inline InputChannelId X{"mouse_delta_x"}; //!< Raw horizontal mouse movement over the last frame
|
||||
static constexpr inline InputChannelId Y{"mouse_delta_y"}; //!< Raw vertical mouse movement over the last frame
|
||||
static constexpr inline InputChannelId Z{"mouse_delta_z"}; //!< Raw mouse wheel movement over the last frame
|
||||
|
||||
//!< All mouse movement ids
|
||||
static const AZStd::array<InputChannelId, 3> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
Z
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -96,7 +108,7 @@ namespace AzFramework
|
||||
//! the system cursor is hidden or visible. When the system cursor has been constrained to
|
||||
//! the active window values will be in the [0.0, 1.0] range, but not when unconstrained.
|
||||
//! See also InputSystemCursorRequests::SetSystemCursorState and GetSystemCursorState.
|
||||
static const InputChannelId SystemCursorPosition;
|
||||
static constexpr inline InputChannelId SystemCursorPosition{"mouse_system_cursor_position"};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Allocator
|
||||
|
||||
@@ -24,31 +24,6 @@ namespace AzFramework
|
||||
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceTouch::Touch::Index0("touch_index_0");
|
||||
const InputChannelId InputDeviceTouch::Touch::Index1("touch_index_1");
|
||||
const InputChannelId InputDeviceTouch::Touch::Index2("touch_index_2");
|
||||
const InputChannelId InputDeviceTouch::Touch::Index3("touch_index_3");
|
||||
const InputChannelId InputDeviceTouch::Touch::Index4("touch_index_4");
|
||||
const InputChannelId InputDeviceTouch::Touch::Index5("touch_index_5");
|
||||
const InputChannelId InputDeviceTouch::Touch::Index6("touch_index_6");
|
||||
const InputChannelId InputDeviceTouch::Touch::Index7("touch_index_7");
|
||||
const InputChannelId InputDeviceTouch::Touch::Index8("touch_index_8");
|
||||
const InputChannelId InputDeviceTouch::Touch::Index9("touch_index_9");
|
||||
const AZStd::array<InputChannelId, 10> InputDeviceTouch::Touch::All =
|
||||
{{
|
||||
Index0,
|
||||
Index1,
|
||||
Index2,
|
||||
Index3,
|
||||
Index4,
|
||||
Index5,
|
||||
Index6,
|
||||
Index7,
|
||||
Index8,
|
||||
Index9
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void InputDeviceTouch::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
|
||||
@@ -38,19 +38,31 @@ namespace AzFramework
|
||||
//! track is arbitrary, but ten seems to be more than sufficient for most game applications.
|
||||
struct Touch
|
||||
{
|
||||
static const InputChannelId Index0; //!< Touch index 0
|
||||
static const InputChannelId Index1; //!< Touch index 1
|
||||
static const InputChannelId Index2; //!< Touch index 2
|
||||
static const InputChannelId Index3; //!< Touch index 3
|
||||
static const InputChannelId Index4; //!< Touch index 4
|
||||
static const InputChannelId Index5; //!< Touch index 5
|
||||
static const InputChannelId Index6; //!< Touch index 6
|
||||
static const InputChannelId Index7; //!< Touch index 7
|
||||
static const InputChannelId Index8; //!< Touch index 8
|
||||
static const InputChannelId Index9; //!< Touch index 9
|
||||
static constexpr inline InputChannelId Index0{"touch_index_0"}; //!< Touch index 0
|
||||
static constexpr inline InputChannelId Index1{"touch_index_1"}; //!< Touch index 1
|
||||
static constexpr inline InputChannelId Index2{"touch_index_2"}; //!< Touch index 2
|
||||
static constexpr inline InputChannelId Index3{"touch_index_3"}; //!< Touch index 3
|
||||
static constexpr inline InputChannelId Index4{"touch_index_4"}; //!< Touch index 4
|
||||
static constexpr inline InputChannelId Index5{"touch_index_5"}; //!< Touch index 5
|
||||
static constexpr inline InputChannelId Index6{"touch_index_6"}; //!< Touch index 6
|
||||
static constexpr inline InputChannelId Index7{"touch_index_7"}; //!< Touch index 7
|
||||
static constexpr inline InputChannelId Index8{"touch_index_8"}; //!< Touch index 8
|
||||
static constexpr inline InputChannelId Index9{"touch_index_9"}; //!< Touch index 9
|
||||
|
||||
//!< All touch input channel ids
|
||||
static const AZStd::array<InputChannelId, 10> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
Index0,
|
||||
Index1,
|
||||
Index2,
|
||||
Index3,
|
||||
Index4,
|
||||
Index5,
|
||||
Index6,
|
||||
Index7,
|
||||
Index8,
|
||||
Index9
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-11
@@ -23,17 +23,6 @@ namespace AzFramework
|
||||
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const InputChannelId InputDeviceVirtualKeyboard::Command::EditEnter("virtual_keyboard_edit_enter");
|
||||
const InputChannelId InputDeviceVirtualKeyboard::Command::EditClear("virtual_keyboard_edit_clear");
|
||||
const InputChannelId InputDeviceVirtualKeyboard::Command::NavigationBack("virtual_keyboard_navigation_back");
|
||||
const AZStd::array<InputChannelId, 3> InputDeviceVirtualKeyboard::Command::All =
|
||||
{{
|
||||
EditClear,
|
||||
EditEnter,
|
||||
NavigationBack
|
||||
}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void InputDeviceVirtualKeyboard::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
|
||||
+9
-4
@@ -39,17 +39,22 @@ namespace AzFramework
|
||||
struct Command
|
||||
{
|
||||
//!< The clear command used to indicate the user wants to clear the active text field
|
||||
static const InputChannelId EditClear;
|
||||
static constexpr inline InputChannelId EditClear{"virtual_keyboard_edit_enter"};
|
||||
|
||||
//!< The enter/return/close command used to indicate the user has finished text editing
|
||||
static const InputChannelId EditEnter;
|
||||
static constexpr inline InputChannelId EditEnter{"virtual_keyboard_edit_clear"};
|
||||
|
||||
//!< The back command used to indicate the user wants to navigate 'backwards'.
|
||||
//!< This is specific to android devices, and does not have an ios equivalent.
|
||||
static const InputChannelId NavigationBack;
|
||||
static constexpr inline InputChannelId NavigationBack{"virtual_keyboard_navigation_back"};
|
||||
|
||||
//!< All virtual keyboard command ids
|
||||
static const AZStd::array<InputChannelId, 3> All;
|
||||
static constexpr inline AZStd::array All
|
||||
{
|
||||
EditClear,
|
||||
EditEnter,
|
||||
NavigationBack
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -8,11 +8,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/RTTI/TypeInfoSimple.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/RTTI/TypeInfoSimple.h>
|
||||
#include <AzCore/base.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -27,7 +26,11 @@ namespace AzFramework
|
||||
AZ_TYPE_INFO(ScreenPoint, "{8472B6C2-527F-44FC-87F8-C226B1A57A97}");
|
||||
ScreenPoint() = default;
|
||||
|
||||
ScreenPoint(int x, int y) : m_x(x), m_y(y) {}
|
||||
ScreenPoint(int x, int y)
|
||||
: m_x(x)
|
||||
, m_y(y)
|
||||
{
|
||||
}
|
||||
|
||||
int m_x; //!< X screen position.
|
||||
int m_y; //!< Y screen position.
|
||||
@@ -42,7 +45,11 @@ namespace AzFramework
|
||||
AZ_TYPE_INFO(ScreenVector, "{1EAA2C62-8FDB-4A28-9FE3-1FA4F1418894}");
|
||||
ScreenVector() = default;
|
||||
|
||||
ScreenVector(int x, int y) : m_x(x), m_y(y) {}
|
||||
ScreenVector(int x, int y)
|
||||
: m_x(x)
|
||||
, m_y(y)
|
||||
{
|
||||
}
|
||||
|
||||
int m_x; //!< X screen delta.
|
||||
int m_y; //!< Y screen delta.
|
||||
@@ -71,14 +78,14 @@ namespace AzFramework
|
||||
|
||||
inline const ScreenPoint operator+(const ScreenPoint& lhs, const ScreenVector& rhs)
|
||||
{
|
||||
ScreenPoint result{lhs};
|
||||
ScreenPoint result{ lhs };
|
||||
result += rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline const ScreenPoint operator-(const ScreenPoint& lhs, const ScreenVector& rhs)
|
||||
{
|
||||
ScreenPoint result{lhs};
|
||||
ScreenPoint result{ lhs };
|
||||
result -= rhs;
|
||||
return result;
|
||||
}
|
||||
@@ -99,14 +106,14 @@ namespace AzFramework
|
||||
|
||||
inline const ScreenVector operator+(const ScreenVector& lhs, const ScreenVector& rhs)
|
||||
{
|
||||
ScreenVector result{lhs};
|
||||
ScreenVector result{ lhs };
|
||||
result += rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline const ScreenVector operator-(const ScreenVector& lhs, const ScreenVector& rhs)
|
||||
{
|
||||
ScreenVector result{lhs};
|
||||
ScreenVector result{ lhs };
|
||||
result -= rhs;
|
||||
return result;
|
||||
}
|
||||
@@ -131,23 +138,25 @@ namespace AzFramework
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
inline ScreenVector& operator*=(ScreenVector& lhs, const float rhs)
|
||||
{
|
||||
lhs.m_x = aznumeric_cast<int>(AZStd::lround(aznumeric_cast<float>(lhs.m_x) * rhs));
|
||||
lhs.m_y = aznumeric_cast<int>(AZStd::lround(aznumeric_cast<float>(lhs.m_y) * rhs));
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline const ScreenVector operator*(const ScreenVector& lhs, const float rhs)
|
||||
{
|
||||
ScreenVector result{ lhs };
|
||||
result *= rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline float ScreenVectorLength(const ScreenVector& screenVector)
|
||||
{
|
||||
return aznumeric_cast<float>(AZStd::sqrt(screenVector.m_x * screenVector.m_x + screenVector.m_y * screenVector.m_y));
|
||||
}
|
||||
|
||||
inline ScreenPoint ScreenPointFromNDC(const AZ::Vector3& screenNDC, const AZ::Vector2& viewportSize)
|
||||
{
|
||||
return ScreenPoint(
|
||||
aznumeric_caster(AZStd::round(screenNDC.GetX() * viewportSize.GetX())),
|
||||
aznumeric_caster(AZStd::round((1.0f - screenNDC.GetY()) * viewportSize.GetY())));
|
||||
}
|
||||
|
||||
inline AZ::Vector2 NDCFromScreenPoint(const ScreenPoint& screenPoint, const AZ::Vector2& viewportSize)
|
||||
{
|
||||
return AZ::Vector2(aznumeric_cast<float>(screenPoint.m_x), viewportSize.GetY() - aznumeric_cast<float>(screenPoint.m_y)) / viewportSize;
|
||||
}
|
||||
|
||||
//! Return an AZ::Vector2 from a ScreenPoint.
|
||||
inline AZ::Vector2 Vector2FromScreenPoint(const ScreenPoint& screenPoint)
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace AzFramework
|
||||
// y-up, z into the screen, x-left
|
||||
//
|
||||
// x -> -x
|
||||
// y -> z
|
||||
// y -> z
|
||||
// z -> y
|
||||
//
|
||||
// the same transform can be used to go to/from z-up - the only difference is the order of
|
||||
@@ -37,15 +37,15 @@ namespace AzFramework
|
||||
// yaw = AZ::Matrix4x4::CreateRotationZ(AZ::DegToRad(180.0f));
|
||||
// conversion = pitch * yaw
|
||||
return AZ::Matrix4x4::CreateFromColumns(
|
||||
AZ::Vector4(-1.0f, 0.0f, 0.0f, 0.0f), AZ::Vector4(0.0f, 0.0f, 1.0f, .0f),
|
||||
AZ::Vector4(0.0f, 1.0f, 0.0f, 0.0f), AZ::Vector4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
AZ::Vector4(-1.0f, 0.0f, 0.0f, 0.0f), AZ::Vector4(0.0f, 0.0f, 1.0f, 0.0f), AZ::Vector4(0.0f, 1.0f, 0.0f, 0.0f),
|
||||
AZ::Vector4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
AZ::Matrix4x4 CameraTransform(const CameraState& cameraState)
|
||||
{
|
||||
return AZ::Matrix4x4::CreateFromColumns(
|
||||
AZ::Vector3ToVector4(cameraState.m_side), AZ::Vector3ToVector4(cameraState.m_forward),
|
||||
AZ::Vector3ToVector4(cameraState.m_up), AZ::Vector3ToVector4(cameraState.m_position, 1.0f));
|
||||
AZ::Vector3ToVector4(cameraState.m_side), AZ::Vector3ToVector4(cameraState.m_forward), AZ::Vector3ToVector4(cameraState.m_up),
|
||||
AZ::Vector3ToVector4(cameraState.m_position, 1.0f));
|
||||
}
|
||||
|
||||
AZ::Matrix4x4 CameraView(const CameraState& cameraState)
|
||||
@@ -63,8 +63,7 @@ namespace AzFramework
|
||||
AZ::Matrix4x4 CameraProjection(const CameraState& cameraState)
|
||||
{
|
||||
return AZ::Matrix4x4::CreateProjection(
|
||||
cameraState.VerticalFovRadian(), AspectRatio(cameraState.m_viewportSize), cameraState.m_nearClip,
|
||||
cameraState.m_farClip);
|
||||
cameraState.VerticalFovRadian(), AspectRatio(cameraState.m_viewportSize), cameraState.m_nearClip, cameraState.m_farClip);
|
||||
}
|
||||
|
||||
AZ::Matrix4x4 InverseCameraProjection(const CameraState& cameraState)
|
||||
@@ -93,12 +92,11 @@ namespace AzFramework
|
||||
const auto cameraWorldTransform = AZ::Transform::CreateFromMatrix3x3AndTranslation(
|
||||
AZ::Matrix3x3::CreateFromMatrix4x4(worldFromView), worldFromView.GetTranslation());
|
||||
return AZ::ViewFrustumAttributes(
|
||||
cameraWorldTransform, AspectRatio(cameraState.m_viewportSize), cameraState.m_fovOrZoom,
|
||||
cameraState.m_nearClip, cameraState.m_farClip);
|
||||
cameraWorldTransform, AspectRatio(cameraState.m_viewportSize), cameraState.m_fovOrZoom, cameraState.m_nearClip,
|
||||
cameraState.m_farClip);
|
||||
}
|
||||
|
||||
AZ::Vector3 WorldToScreenNDC(
|
||||
const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection)
|
||||
AZ::Vector3 WorldToScreenNdc(const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection)
|
||||
{
|
||||
// transform the world space position to clip space
|
||||
const auto clipSpacePosition = cameraProjection * cameraView * AZ::Vector3ToVector4(worldPosition, 1.0f);
|
||||
@@ -108,25 +106,24 @@ namespace AzFramework
|
||||
return (AZ::Vector4ToVector3(ndcPosition) + AZ::Vector3::CreateOne()) * 0.5f;
|
||||
}
|
||||
|
||||
|
||||
ScreenPoint WorldToScreen(
|
||||
const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection,
|
||||
const AZ::Vector3& worldPosition,
|
||||
const AZ::Matrix4x4& cameraView,
|
||||
const AZ::Matrix4x4& cameraProjection,
|
||||
const AZ::Vector2& viewportSize)
|
||||
{
|
||||
const auto ndcNormalizedPosition = WorldToScreenNDC(worldPosition, cameraView, cameraProjection);
|
||||
const auto ndcNormalizedPosition = WorldToScreenNdc(worldPosition, cameraView, cameraProjection);
|
||||
// scale ndc position by screen dimensions to return screen position
|
||||
return ScreenPointFromNDC(ndcNormalizedPosition, viewportSize);
|
||||
return ScreenPointFromNdc(AZ::Vector3ToVector2(ndcNormalizedPosition), viewportSize);
|
||||
}
|
||||
|
||||
ScreenPoint WorldToScreen(const AZ::Vector3& worldPosition, const CameraState& cameraState)
|
||||
{
|
||||
return WorldToScreen(
|
||||
worldPosition, CameraView(cameraState), CameraProjection(cameraState), cameraState.m_viewportSize);
|
||||
return WorldToScreen(worldPosition, CameraView(cameraState), CameraProjection(cameraState), cameraState.m_viewportSize);
|
||||
}
|
||||
|
||||
AZ::Vector3 ScreenNDCToWorld(
|
||||
const AZ::Vector2& normalizedScreenPosition, const AZ::Matrix4x4& inverseCameraView,
|
||||
const AZ::Matrix4x4& inverseCameraProjection)
|
||||
AZ::Vector3 ScreenNdcToWorld(
|
||||
const AZ::Vector2& normalizedScreenPosition, const AZ::Matrix4x4& inverseCameraView, const AZ::Matrix4x4& inverseCameraProjection)
|
||||
{
|
||||
// convert screen space coordinates from <0, 1> to <-1,1> range
|
||||
const auto ndcPosition = normalizedScreenPosition * 2.0f - AZ::Vector2::CreateOne();
|
||||
@@ -142,18 +139,19 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
AZ::Vector3 ScreenToWorld(
|
||||
const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView,
|
||||
const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize)
|
||||
const ScreenPoint& screenPosition,
|
||||
const AZ::Matrix4x4& inverseCameraView,
|
||||
const AZ::Matrix4x4& inverseCameraProjection,
|
||||
const AZ::Vector2& viewportSize)
|
||||
{
|
||||
const auto normalizedScreenPosition = NDCFromScreenPoint(screenPosition, viewportSize);
|
||||
const auto normalizedScreenPosition = NdcFromScreenPoint(screenPosition, viewportSize);
|
||||
|
||||
return ScreenNDCToWorld(normalizedScreenPosition, inverseCameraView, inverseCameraProjection);
|
||||
return ScreenNdcToWorld(normalizedScreenPosition, inverseCameraView, inverseCameraProjection);
|
||||
}
|
||||
|
||||
AZ::Vector3 ScreenToWorld(const ScreenPoint& screenPosition, const CameraState& cameraState)
|
||||
{
|
||||
return ScreenToWorld(
|
||||
screenPosition, InverseCameraView(cameraState), InverseCameraProjection(cameraState),
|
||||
cameraState.m_viewportSize);
|
||||
screenPosition, InverseCameraView(cameraState), InverseCameraProjection(cameraState), cameraState.m_viewportSize);
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -8,26 +8,42 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class Frustum;
|
||||
class Matrix4x4;
|
||||
class Vector3;
|
||||
struct ViewFrustumAttributes;
|
||||
} // namespace AZ
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
struct CameraState;
|
||||
struct ScreenPoint;
|
||||
struct ViewportInfo;
|
||||
|
||||
//! Projects a position in world space to screen space normalized device coordinates for the given camera.
|
||||
AZ::Vector3 WorldToScreenNDC(
|
||||
const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection);
|
||||
//! Returns a position in screen space (in the range [0-viewportSize.x, 0-viewportSize.y]) from normalized device
|
||||
//! coordinates (in the range 0.0-1.0).
|
||||
inline ScreenPoint ScreenPointFromNdc(const AZ::Vector2& screenNdc, const AZ::Vector2& viewportSize)
|
||||
{
|
||||
return ScreenPoint(
|
||||
aznumeric_cast<int>(AZStd::lround(screenNdc.GetX() * viewportSize.GetX())),
|
||||
aznumeric_cast<int>(AZStd::lround((1.0f - screenNdc.GetY()) * viewportSize.GetY())));
|
||||
}
|
||||
|
||||
//! Returns a position in normalized device coordinates (in the range [0.0-1.0, 0.0-1.0]) from a
|
||||
//! screen space position (in the range [0-viewportSize.x, 0-viewportSize.y]).
|
||||
inline AZ::Vector2 NdcFromScreenPoint(const ScreenPoint& screenPoint, const AZ::Vector2& viewportSize)
|
||||
{
|
||||
return AZ::Vector2(aznumeric_cast<float>(screenPoint.m_x), viewportSize.GetY() - aznumeric_cast<float>(screenPoint.m_y)) /
|
||||
viewportSize;
|
||||
}
|
||||
|
||||
//! Projects a position in world space to screen space normalized device coordinates for the given camera.
|
||||
AZ::Vector3 WorldToScreenNdc(const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection);
|
||||
|
||||
//! Projects a position in world space to screen space for the given camera.
|
||||
ScreenPoint WorldToScreen(const AZ::Vector3& worldPosition, const CameraState& cameraState);
|
||||
@@ -35,7 +51,9 @@ namespace AzFramework
|
||||
//! Overload of WorldToScreen that accepts camera values that can be precomputed if this function
|
||||
//! is called many times in a loop.
|
||||
ScreenPoint WorldToScreen(
|
||||
const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection,
|
||||
const AZ::Vector3& worldPosition,
|
||||
const AZ::Matrix4x4& cameraView,
|
||||
const AZ::Matrix4x4& cameraProjection,
|
||||
const AZ::Vector2& viewportSize);
|
||||
|
||||
//! Unprojects a position in screen space pixel coordinates to world space.
|
||||
@@ -45,14 +63,15 @@ namespace AzFramework
|
||||
//! Overload of ScreenToWorld that accepts camera values that can be precomputed if this function
|
||||
//! is called many times in a loop.
|
||||
AZ::Vector3 ScreenToWorld(
|
||||
const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView,
|
||||
const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize);
|
||||
const ScreenPoint& screenPosition,
|
||||
const AZ::Matrix4x4& inverseCameraView,
|
||||
const AZ::Matrix4x4& inverseCameraProjection,
|
||||
const AZ::Vector2& viewportSize);
|
||||
|
||||
//! Unprojects a position in screen space normalized device coordinates to world space.
|
||||
//! Note: The position returned will be on the near clip plane of the camera in world space.
|
||||
AZ::Vector3 ScreenNDCToWorld(
|
||||
const AZ::Vector2& ndcPosition, const AZ::Matrix4x4& inverseCameraView,
|
||||
const AZ::Matrix4x4& inverseCameraProjection);
|
||||
AZ::Vector3 ScreenNdcToWorld(
|
||||
const AZ::Vector2& ndcPosition, const AZ::Matrix4x4& inverseCameraView, const AZ::Matrix4x4& inverseCameraProjection);
|
||||
|
||||
//! Returns the camera projection for the current camera state.
|
||||
AZ::Matrix4x4 CameraProjection(const CameraState& cameraState);
|
||||
|
||||
@@ -95,4 +95,4 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
+20
-25
@@ -6,29 +6,26 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI_Platform.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include "Application_Linux_xcb.h"
|
||||
#include <AzFramework/XcbApplication.h>
|
||||
#include <AzFramework/XcbEventHandler.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
namespace AzFramework
|
||||
{
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class LinuxXcbConnectionManagerImpl
|
||||
: public LinuxXcbConnectionManagerBus::Handler
|
||||
class XcbConnectionManagerImpl
|
||||
: public XcbConnectionManagerBus::Handler
|
||||
{
|
||||
public:
|
||||
LinuxXcbConnectionManagerImpl()
|
||||
XcbConnectionManagerImpl()
|
||||
{
|
||||
m_xcbConnection = xcb_connect(nullptr, nullptr);
|
||||
AZ_Error("ApplicationLinux", m_xcbConnection != nullptr, "Unable to connect to X11 Server.");
|
||||
LinuxXcbConnectionManagerBus::Handler::BusConnect();
|
||||
AZ_Error("Application", m_xcbConnection != nullptr, "Unable to connect to X11 Server.");
|
||||
XcbConnectionManagerBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
~LinuxXcbConnectionManagerImpl()
|
||||
~XcbConnectionManagerImpl() override
|
||||
{
|
||||
LinuxXcbConnectionManagerBus::Handler::BusDisconnect();
|
||||
XcbConnectionManagerBus::Handler::BusDisconnect();
|
||||
xcb_disconnect(m_xcbConnection);
|
||||
}
|
||||
|
||||
@@ -42,53 +39,51 @@ namespace AzFramework
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ApplicationLinux_xcb::ApplicationLinux_xcb()
|
||||
XcbApplication::XcbApplication()
|
||||
{
|
||||
LinuxLifecycleEvents::Bus::Handler::BusConnect();
|
||||
m_xcbConnectionManager = AZStd::make_unique<LinuxXcbConnectionManagerImpl>();
|
||||
if (LinuxXcbConnectionManagerInterface::Get() == nullptr)
|
||||
m_xcbConnectionManager = AZStd::make_unique<XcbConnectionManagerImpl>();
|
||||
if (XcbConnectionManagerInterface::Get() == nullptr)
|
||||
{
|
||||
LinuxXcbConnectionManagerInterface::Register(m_xcbConnectionManager.get());
|
||||
XcbConnectionManagerInterface::Register(m_xcbConnectionManager.get());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ApplicationLinux_xcb::~ApplicationLinux_xcb()
|
||||
XcbApplication::~XcbApplication()
|
||||
{
|
||||
if (LinuxXcbConnectionManagerInterface::Get() == m_xcbConnectionManager.get())
|
||||
if (XcbConnectionManagerInterface::Get() == m_xcbConnectionManager.get())
|
||||
{
|
||||
LinuxXcbConnectionManagerInterface::Unregister(m_xcbConnectionManager.get());
|
||||
XcbConnectionManagerInterface::Unregister(m_xcbConnectionManager.get());
|
||||
}
|
||||
m_xcbConnectionManager.reset();
|
||||
LinuxLifecycleEvents::Bus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void ApplicationLinux_xcb::PumpSystemEventLoopOnce()
|
||||
void XcbApplication::PumpSystemEventLoopOnce()
|
||||
{
|
||||
if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection())
|
||||
{
|
||||
if (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection))
|
||||
{
|
||||
LinuxXcbEventHandlerBus::Broadcast(&LinuxXcbEventHandlerBus::Events::HandleXcbEvent, event);
|
||||
XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event);
|
||||
free(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void ApplicationLinux_xcb::PumpSystemEventLoopUntilEmpty()
|
||||
void XcbApplication::PumpSystemEventLoopUntilEmpty()
|
||||
{
|
||||
if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection())
|
||||
{
|
||||
while (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection))
|
||||
{
|
||||
LinuxXcbEventHandlerBus::Broadcast(&LinuxXcbEventHandlerBus::Events::HandleXcbEvent, event);
|
||||
XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event);
|
||||
free(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
|
||||
} // namespace AzFramework
|
||||
+7
-13
@@ -5,27 +5,24 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI_Platform.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzFramework/XcbConnectionManager.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
namespace AzFramework
|
||||
{
|
||||
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class ApplicationLinux_xcb
|
||||
class XcbApplication
|
||||
: public Application::Implementation
|
||||
, public LinuxLifecycleEvents::Bus::Handler
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AZ_CLASS_ALLOCATOR(ApplicationLinux_xcb, AZ::SystemAllocator, 0);
|
||||
ApplicationLinux_xcb();
|
||||
~ApplicationLinux_xcb() override;
|
||||
AZ_CLASS_ALLOCATOR(XcbApplication, AZ::SystemAllocator, 0);
|
||||
XcbApplication();
|
||||
~XcbApplication() override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Application::Implementation
|
||||
@@ -33,9 +30,6 @@ namespace AzFramework
|
||||
void PumpSystemEventLoopUntilEmpty() override;
|
||||
|
||||
private:
|
||||
AZStd::unique_ptr<LinuxXcbConnectionManager> m_xcbConnectionManager;
|
||||
AZStd::unique_ptr<XcbConnectionManager> m_xcbConnectionManager;
|
||||
};
|
||||
|
||||
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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/EBus/EBus.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class XcbConnectionManager
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(XcbConnectionManager, "{1F756E14-8D74-42FD-843C-4863307710DB}");
|
||||
|
||||
virtual ~XcbConnectionManager() = default;
|
||||
|
||||
virtual xcb_connection_t* GetXcbConnection() const = 0;
|
||||
};
|
||||
|
||||
class XcbConnectionManagerBusTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
|
||||
using XcbConnectionManagerBus = AZ::EBus<XcbConnectionManager, XcbConnectionManagerBusTraits>;
|
||||
using XcbConnectionManagerInterface = AZ::Interface<XcbConnectionManager>;
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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/EBus/EBus.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class XcbEventHandler
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(XcbEventHandler, "{3F756E14-8D74-42FD-843C-4863307710DB}");
|
||||
|
||||
virtual ~XcbEventHandler() = default;
|
||||
|
||||
virtual void HandleXcbEvent(xcb_generic_event_t* event) = 0;
|
||||
};
|
||||
|
||||
class XcbEventHandlerBusTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
|
||||
using XcbEventHandlerBus = AZ::EBus<XcbEventHandler, XcbEventHandlerBusTraits>;
|
||||
} // namespace AzFramework
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* 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 <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/XcbEventHandler.h>
|
||||
#include <AzFramework/XcbConnectionManager.h>
|
||||
#include <AzFramework/XcbInputDeviceKeyboard.h>
|
||||
|
||||
#define explicit ExplicitIsACXXKeyword
|
||||
#include <xcb/xkb.h>
|
||||
#undef explicit
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-x11.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
XcbInputDeviceKeyboard::XcbInputDeviceKeyboard(InputDeviceKeyboard& inputDevice)
|
||||
: InputDeviceKeyboard::Implementation(inputDevice)
|
||||
{
|
||||
XcbEventHandlerBus::Handler::BusConnect();
|
||||
|
||||
auto* interface = AzFramework::XcbConnectionManagerInterface::Get();
|
||||
if (!interface)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "XCB interface not available");
|
||||
return;
|
||||
}
|
||||
|
||||
auto* connection = interface->GetXcbConnection();
|
||||
if (!connection)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "XCB connection not available");
|
||||
return;
|
||||
}
|
||||
|
||||
XcbStdFreePtr<xcb_xkb_use_extension_reply_t> xkbUseExtensionReply{
|
||||
xcb_xkb_use_extension_reply(connection, xcb_xkb_use_extension(connection, 1, 0), nullptr)
|
||||
};
|
||||
if (!xkbUseExtensionReply)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "Failed to initialize the xkb extension");
|
||||
return;
|
||||
}
|
||||
if (!xkbUseExtensionReply->supported)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "The X server does not support the xkb extension");
|
||||
return;
|
||||
}
|
||||
|
||||
m_coreDeviceId = xkb_x11_get_core_keyboard_device_id(connection);
|
||||
|
||||
m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
|
||||
m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), connection, m_coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS));
|
||||
m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), connection, m_coreDeviceId));
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
bool XcbInputDeviceKeyboard::IsConnected() const
|
||||
{
|
||||
auto* connection = AzFramework::XcbConnectionManagerInterface::Get()->GetXcbConnection();
|
||||
return connection && !xcb_connection_has_error(connection);
|
||||
}
|
||||
|
||||
bool XcbInputDeviceKeyboard::HasTextEntryStarted() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void XcbInputDeviceKeyboard::TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options)
|
||||
{
|
||||
}
|
||||
|
||||
void XcbInputDeviceKeyboard::TextEntryStop()
|
||||
{
|
||||
}
|
||||
|
||||
void XcbInputDeviceKeyboard::TickInputDevice()
|
||||
{
|
||||
ProcessRawEventQueues();
|
||||
}
|
||||
|
||||
void XcbInputDeviceKeyboard::HandleXcbEvent(xcb_generic_event_t* event)
|
||||
{
|
||||
if (!m_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event->response_type & ~0x80)
|
||||
{
|
||||
case XCB_KEY_PRESS:
|
||||
{
|
||||
auto* keyPress = reinterpret_cast<xcb_key_press_event_t*>(event);
|
||||
|
||||
const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail);
|
||||
if (key)
|
||||
{
|
||||
QueueRawKeyEvent(*key, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XCB_KEY_RELEASE:
|
||||
{
|
||||
auto* keyRelease = reinterpret_cast<xcb_key_release_event_t*>(event);
|
||||
|
||||
const InputChannelId* key = InputChannelFromKeyEvent(keyRelease->detail);
|
||||
if (key)
|
||||
{
|
||||
QueueRawKeyEvent(*key, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] const InputChannelId* XcbInputDeviceKeyboard::InputChannelFromKeyEvent(xcb_keycode_t code) const
|
||||
{
|
||||
const xcb_keysym_t keysym = xkb_state_key_get_one_sym(m_xkbState.get(), code);
|
||||
|
||||
switch(keysym)
|
||||
{
|
||||
case XKB_KEY_0: return &InputDeviceKeyboard::Key::Alphanumeric0;
|
||||
case XKB_KEY_1: return &InputDeviceKeyboard::Key::Alphanumeric1;
|
||||
case XKB_KEY_2: return &InputDeviceKeyboard::Key::Alphanumeric2;
|
||||
case XKB_KEY_3: return &InputDeviceKeyboard::Key::Alphanumeric3;
|
||||
case XKB_KEY_4: return &InputDeviceKeyboard::Key::Alphanumeric4;
|
||||
case XKB_KEY_5: return &InputDeviceKeyboard::Key::Alphanumeric5;
|
||||
case XKB_KEY_6: return &InputDeviceKeyboard::Key::Alphanumeric6;
|
||||
case XKB_KEY_7: return &InputDeviceKeyboard::Key::Alphanumeric7;
|
||||
case XKB_KEY_8: return &InputDeviceKeyboard::Key::Alphanumeric8;
|
||||
case XKB_KEY_9: return &InputDeviceKeyboard::Key::Alphanumeric9;
|
||||
case XKB_KEY_A:
|
||||
case XKB_KEY_a: return &InputDeviceKeyboard::Key::AlphanumericA;
|
||||
case XKB_KEY_B:
|
||||
case XKB_KEY_b: return &InputDeviceKeyboard::Key::AlphanumericB;
|
||||
case XKB_KEY_C:
|
||||
case XKB_KEY_c: return &InputDeviceKeyboard::Key::AlphanumericC;
|
||||
case XKB_KEY_D:
|
||||
case XKB_KEY_d: return &InputDeviceKeyboard::Key::AlphanumericD;
|
||||
case XKB_KEY_E:
|
||||
case XKB_KEY_e: return &InputDeviceKeyboard::Key::AlphanumericE;
|
||||
case XKB_KEY_F:
|
||||
case XKB_KEY_f: return &InputDeviceKeyboard::Key::AlphanumericF;
|
||||
case XKB_KEY_G:
|
||||
case XKB_KEY_g: return &InputDeviceKeyboard::Key::AlphanumericG;
|
||||
case XKB_KEY_H:
|
||||
case XKB_KEY_h: return &InputDeviceKeyboard::Key::AlphanumericH;
|
||||
case XKB_KEY_I:
|
||||
case XKB_KEY_i: return &InputDeviceKeyboard::Key::AlphanumericI;
|
||||
case XKB_KEY_J:
|
||||
case XKB_KEY_j: return &InputDeviceKeyboard::Key::AlphanumericJ;
|
||||
case XKB_KEY_K:
|
||||
case XKB_KEY_k: return &InputDeviceKeyboard::Key::AlphanumericK;
|
||||
case XKB_KEY_L:
|
||||
case XKB_KEY_l: return &InputDeviceKeyboard::Key::AlphanumericL;
|
||||
case XKB_KEY_M:
|
||||
case XKB_KEY_m: return &InputDeviceKeyboard::Key::AlphanumericM;
|
||||
case XKB_KEY_N:
|
||||
case XKB_KEY_n: return &InputDeviceKeyboard::Key::AlphanumericN;
|
||||
case XKB_KEY_O:
|
||||
case XKB_KEY_o: return &InputDeviceKeyboard::Key::AlphanumericO;
|
||||
case XKB_KEY_P:
|
||||
case XKB_KEY_p: return &InputDeviceKeyboard::Key::AlphanumericP;
|
||||
case XKB_KEY_Q:
|
||||
case XKB_KEY_q: return &InputDeviceKeyboard::Key::AlphanumericQ;
|
||||
case XKB_KEY_R:
|
||||
case XKB_KEY_r: return &InputDeviceKeyboard::Key::AlphanumericR;
|
||||
case XKB_KEY_S:
|
||||
case XKB_KEY_s: return &InputDeviceKeyboard::Key::AlphanumericS;
|
||||
case XKB_KEY_T:
|
||||
case XKB_KEY_t: return &InputDeviceKeyboard::Key::AlphanumericT;
|
||||
case XKB_KEY_U:
|
||||
case XKB_KEY_u: return &InputDeviceKeyboard::Key::AlphanumericU;
|
||||
case XKB_KEY_V:
|
||||
case XKB_KEY_v: return &InputDeviceKeyboard::Key::AlphanumericV;
|
||||
case XKB_KEY_W:
|
||||
case XKB_KEY_w: return &InputDeviceKeyboard::Key::AlphanumericW;
|
||||
case XKB_KEY_X:
|
||||
case XKB_KEY_x: return &InputDeviceKeyboard::Key::AlphanumericX;
|
||||
case XKB_KEY_Y:
|
||||
case XKB_KEY_y: return &InputDeviceKeyboard::Key::AlphanumericY;
|
||||
case XKB_KEY_Z:
|
||||
case XKB_KEY_z: return &InputDeviceKeyboard::Key::AlphanumericZ;
|
||||
case XKB_KEY_BackSpace: return &InputDeviceKeyboard::Key::EditBackspace;
|
||||
case XKB_KEY_Caps_Lock: return &InputDeviceKeyboard::Key::EditCapsLock;
|
||||
case XKB_KEY_Return: return &InputDeviceKeyboard::Key::EditEnter;
|
||||
case XKB_KEY_space: return &InputDeviceKeyboard::Key::EditSpace;
|
||||
case XKB_KEY_Tab: return &InputDeviceKeyboard::Key::EditTab;
|
||||
case XKB_KEY_Escape: return &InputDeviceKeyboard::Key::Escape;
|
||||
case XKB_KEY_F1: return &InputDeviceKeyboard::Key::Function01;
|
||||
case XKB_KEY_F2: return &InputDeviceKeyboard::Key::Function02;
|
||||
case XKB_KEY_F3: return &InputDeviceKeyboard::Key::Function03;
|
||||
case XKB_KEY_F4: return &InputDeviceKeyboard::Key::Function04;
|
||||
case XKB_KEY_F5: return &InputDeviceKeyboard::Key::Function05;
|
||||
case XKB_KEY_F6: return &InputDeviceKeyboard::Key::Function06;
|
||||
case XKB_KEY_F7: return &InputDeviceKeyboard::Key::Function07;
|
||||
case XKB_KEY_F8: return &InputDeviceKeyboard::Key::Function08;
|
||||
case XKB_KEY_F9: return &InputDeviceKeyboard::Key::Function09;
|
||||
case XKB_KEY_F10: return &InputDeviceKeyboard::Key::Function10;
|
||||
case XKB_KEY_F11: return &InputDeviceKeyboard::Key::Function11;
|
||||
case XKB_KEY_F12: return &InputDeviceKeyboard::Key::Function12;
|
||||
case XKB_KEY_F13: return &InputDeviceKeyboard::Key::Function13;
|
||||
case XKB_KEY_F14: return &InputDeviceKeyboard::Key::Function14;
|
||||
case XKB_KEY_F15: return &InputDeviceKeyboard::Key::Function15;
|
||||
case XKB_KEY_F16: return &InputDeviceKeyboard::Key::Function16;
|
||||
case XKB_KEY_F17: return &InputDeviceKeyboard::Key::Function17;
|
||||
case XKB_KEY_F18: return &InputDeviceKeyboard::Key::Function18;
|
||||
case XKB_KEY_F19: return &InputDeviceKeyboard::Key::Function19;
|
||||
case XKB_KEY_F20: return &InputDeviceKeyboard::Key::Function20;
|
||||
case XKB_KEY_Alt_L: return &InputDeviceKeyboard::Key::ModifierAltL;
|
||||
case XKB_KEY_Alt_R: return &InputDeviceKeyboard::Key::ModifierAltR;
|
||||
case XKB_KEY_Control_L: return &InputDeviceKeyboard::Key::ModifierCtrlL;
|
||||
case XKB_KEY_Control_R: return &InputDeviceKeyboard::Key::ModifierCtrlR;
|
||||
case XKB_KEY_Shift_L: return &InputDeviceKeyboard::Key::ModifierShiftL;
|
||||
case XKB_KEY_Shift_R: return &InputDeviceKeyboard::Key::ModifierShiftR;
|
||||
case XKB_KEY_Super_L: return &InputDeviceKeyboard::Key::ModifierSuperL;
|
||||
case XKB_KEY_Super_R: return &InputDeviceKeyboard::Key::ModifierSuperR;
|
||||
case XKB_KEY_Down: return &InputDeviceKeyboard::Key::NavigationArrowDown;
|
||||
case XKB_KEY_Left: return &InputDeviceKeyboard::Key::NavigationArrowLeft;
|
||||
case XKB_KEY_Right: return &InputDeviceKeyboard::Key::NavigationArrowRight;
|
||||
case XKB_KEY_Up: return &InputDeviceKeyboard::Key::NavigationArrowUp;
|
||||
case XKB_KEY_Delete: return &InputDeviceKeyboard::Key::NavigationDelete;
|
||||
case XKB_KEY_End: return &InputDeviceKeyboard::Key::NavigationEnd;
|
||||
case XKB_KEY_Home: return &InputDeviceKeyboard::Key::NavigationHome;
|
||||
case XKB_KEY_Insert: return &InputDeviceKeyboard::Key::NavigationInsert;
|
||||
case XKB_KEY_Page_Down: return &InputDeviceKeyboard::Key::NavigationPageDown;
|
||||
case XKB_KEY_Page_Up: return &InputDeviceKeyboard::Key::NavigationPageUp;
|
||||
case XKB_KEY_Num_Lock: return &InputDeviceKeyboard::Key::NumLock;
|
||||
case XKB_KEY_KP_0: return &InputDeviceKeyboard::Key::NumPad0;
|
||||
case XKB_KEY_KP_1: return &InputDeviceKeyboard::Key::NumPad1;
|
||||
case XKB_KEY_KP_2: return &InputDeviceKeyboard::Key::NumPad2;
|
||||
case XKB_KEY_KP_3: return &InputDeviceKeyboard::Key::NumPad3;
|
||||
case XKB_KEY_KP_4: return &InputDeviceKeyboard::Key::NumPad4;
|
||||
case XKB_KEY_KP_5: return &InputDeviceKeyboard::Key::NumPad5;
|
||||
case XKB_KEY_KP_6: return &InputDeviceKeyboard::Key::NumPad6;
|
||||
case XKB_KEY_KP_7: return &InputDeviceKeyboard::Key::NumPad7;
|
||||
case XKB_KEY_KP_8: return &InputDeviceKeyboard::Key::NumPad8;
|
||||
case XKB_KEY_KP_9: return &InputDeviceKeyboard::Key::NumPad9;
|
||||
case XKB_KEY_KP_Add: return &InputDeviceKeyboard::Key::NumPadAdd;
|
||||
case XKB_KEY_KP_Decimal: return &InputDeviceKeyboard::Key::NumPadDecimal;
|
||||
case XKB_KEY_KP_Divide: return &InputDeviceKeyboard::Key::NumPadDivide;
|
||||
case XKB_KEY_KP_Enter: return &InputDeviceKeyboard::Key::NumPadEnter;
|
||||
case XKB_KEY_KP_Multiply: return &InputDeviceKeyboard::Key::NumPadMultiply;
|
||||
case XKB_KEY_KP_Subtract: return &InputDeviceKeyboard::Key::NumPadSubtract;
|
||||
case XKB_KEY_apostrophe: return &InputDeviceKeyboard::Key::PunctuationApostrophe;
|
||||
case XKB_KEY_backslash: return &InputDeviceKeyboard::Key::PunctuationBackslash;
|
||||
case XKB_KEY_bracketleft: return &InputDeviceKeyboard::Key::PunctuationBracketL;
|
||||
case XKB_KEY_bracketright: return &InputDeviceKeyboard::Key::PunctuationBracketR;
|
||||
case XKB_KEY_comma: return &InputDeviceKeyboard::Key::PunctuationComma;
|
||||
case XKB_KEY_equal: return &InputDeviceKeyboard::Key::PunctuationEquals;
|
||||
case XKB_KEY_hyphen: return &InputDeviceKeyboard::Key::PunctuationHyphen;
|
||||
case XKB_KEY_period: return &InputDeviceKeyboard::Key::PunctuationPeriod;
|
||||
case XKB_KEY_semicolon: return &InputDeviceKeyboard::Key::PunctuationSemicolon;
|
||||
case XKB_KEY_slash: return &InputDeviceKeyboard::Key::PunctuationSlash;
|
||||
case XKB_KEY_grave:
|
||||
case XKB_KEY_asciitilde: return &InputDeviceKeyboard::Key::PunctuationTilde;
|
||||
case XKB_KEY_ISO_Group_Shift: return &InputDeviceKeyboard::Key::SupplementaryISO;
|
||||
case XKB_KEY_Pause: return &InputDeviceKeyboard::Key::WindowsSystemPause;
|
||||
case XKB_KEY_Print: return &InputDeviceKeyboard::Key::WindowsSystemPrint;
|
||||
case XKB_KEY_Scroll_Lock: return &InputDeviceKeyboard::Key::WindowsSystemScrollLock;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/XcbEventHandler.h>
|
||||
#include <AzFramework/XcbInterface.h>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class XcbInputDeviceKeyboard
|
||||
: public InputDeviceKeyboard::Implementation
|
||||
, public XcbEventHandlerBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(XcbInputDeviceKeyboard, AZ::SystemAllocator, 0);
|
||||
|
||||
using InputDeviceKeyboard::Implementation::Implementation;
|
||||
XcbInputDeviceKeyboard(InputDeviceKeyboard& inputDevice);
|
||||
|
||||
bool IsConnected() const override;
|
||||
|
||||
bool HasTextEntryStarted() const override;
|
||||
void TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options) override;
|
||||
void TextEntryStop() override;
|
||||
void TickInputDevice() override;
|
||||
|
||||
void HandleXcbEvent(xcb_generic_event_t* event) override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const;
|
||||
|
||||
XcbUniquePtr<xkb_context, xkb_context_unref> m_xkbContext;
|
||||
XcbUniquePtr<xkb_keymap, xkb_keymap_unref> m_xkbKeymap;
|
||||
XcbUniquePtr<xkb_state, xkb_state_unref> m_xkbState;
|
||||
int m_coreDeviceId{-1};
|
||||
bool m_initialized{false};
|
||||
};
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 <xcb/xcb.h>
|
||||
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
// @brief Wrap a function pointer in a type
|
||||
// This serves as a convenient way to wrap a function pointer in a given
|
||||
// type. That type can then be used in a `unique_ptr` or `shared_ptr`.
|
||||
// Using a type instead of a function pointer by value prevents the need to
|
||||
// copy the pointer when copying the smart poiner.
|
||||
template<auto Callable>
|
||||
struct XcbDeleterFreeFunctionWrapper
|
||||
{
|
||||
using value_type = decltype(Callable);
|
||||
static constexpr value_type s_value = Callable;
|
||||
constexpr operator value_type() const noexcept
|
||||
{
|
||||
return s_value;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, auto fn>
|
||||
using XcbUniquePtr = AZStd::unique_ptr<T, XcbDeleterFreeFunctionWrapper<fn>>;
|
||||
|
||||
template<typename T>
|
||||
using XcbStdFreePtr = XcbUniquePtr<T, ::free>;
|
||||
} // namespace AzFramework
|
||||
+22
-29
@@ -6,41 +6,37 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI_Platform.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzFramework/Windowing/NativeWindow.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <AzFramework/XcbNativeWindow.h>
|
||||
#include <AzFramework/XcbConnectionManager.h>
|
||||
|
||||
#include "NativeWindow_Linux_xcb.h"
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
|
||||
[[maybe_unused]] const char LinuxXcbErrorWindow[] = "NativeWindow_Linux_xcb";
|
||||
[[maybe_unused]] const char XcbErrorWindow[] = "XcbNativeWindow";
|
||||
static constexpr uint8_t s_XcbFormatDataSize = 32; // Format indicator for xcb for client messages
|
||||
static constexpr uint16_t s_DefaultXcbWindowBorderWidth = 4; // The default border with in pixels if a border was specified
|
||||
static constexpr uint8_t s_XcbResponseTypeMask = 0x7f; // Mask to extract the specific event type from an xcb event
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
NativeWindowImpl_Linux_xcb::NativeWindowImpl_Linux_xcb()
|
||||
XcbNativeWindow::XcbNativeWindow()
|
||||
: NativeWindow::Implementation()
|
||||
{
|
||||
if (auto xcbConnectionManager = AzFramework::LinuxXcbConnectionManagerInterface::Get();
|
||||
if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get();
|
||||
xcbConnectionManager != nullptr)
|
||||
{
|
||||
m_xcbConnection = xcbConnectionManager->GetXcbConnection();
|
||||
}
|
||||
AZ_Error(LinuxXcbErrorWindow, m_xcbConnection != nullptr, "Unable to get XCB Connection");
|
||||
AZ_Error(XcbErrorWindow, m_xcbConnection != nullptr, "Unable to get XCB Connection");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
NativeWindowImpl_Linux_xcb::~NativeWindowImpl_Linux_xcb()
|
||||
{
|
||||
}
|
||||
XcbNativeWindow::~XcbNativeWindow() = default;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void NativeWindowImpl_Linux_xcb::InitWindow(const AZStd::string& title,
|
||||
void XcbNativeWindow::InitWindow(const AZStd::string& title,
|
||||
const WindowGeometry& geometry,
|
||||
const WindowStyleMasks& styleMasks)
|
||||
{
|
||||
@@ -98,13 +94,13 @@ namespace AzFramework
|
||||
|
||||
xcb_intern_atom_cookie_t cookieProtocol = xcb_intern_atom(m_xcbConnection, 1, strlen(wmProtocolString), wmProtocolString);
|
||||
xcb_intern_atom_reply_t* replyProtocol = xcb_intern_atom_reply(m_xcbConnection, cookieProtocol, nullptr);
|
||||
AZ_Error(LinuxXcbErrorWindow, replyProtocol != nullptr, "Unable to query xcb '%s' atom", wmProtocolString);
|
||||
AZ_Error(XcbErrorWindow, replyProtocol != nullptr, "Unable to query xcb '%s' atom", wmProtocolString);
|
||||
m_xcbAtomProtocols = replyProtocol->atom;
|
||||
|
||||
const static char* wmDeleteWindowString = "WM_DELETE_WINDOW";
|
||||
xcb_intern_atom_cookie_t cookieDeleteWindow = xcb_intern_atom(m_xcbConnection, 0, strlen(wmDeleteWindowString), wmDeleteWindowString);
|
||||
xcb_intern_atom_reply_t* replyDeleteWindow = xcb_intern_atom_reply(m_xcbConnection, cookieDeleteWindow, nullptr);
|
||||
AZ_Error(LinuxXcbErrorWindow, replyDeleteWindow != nullptr, "Unable to query xcb '%s' atom", wmDeleteWindowString);
|
||||
AZ_Error(XcbErrorWindow, replyDeleteWindow != nullptr, "Unable to query xcb '%s' atom", wmDeleteWindowString);
|
||||
m_xcbAtomDeleteWindow = replyDeleteWindow->atom;
|
||||
|
||||
xcbCheckResult = xcb_change_property_checked(m_xcbConnection,
|
||||
@@ -123,9 +119,9 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void NativeWindowImpl_Linux_xcb::Activate()
|
||||
void XcbNativeWindow::Activate()
|
||||
{
|
||||
LinuxXcbEventHandlerBus::Handler::BusConnect();
|
||||
XcbEventHandlerBus::Handler::BusConnect();
|
||||
|
||||
if (!m_activated) // nothing to do if window was already activated
|
||||
{
|
||||
@@ -137,7 +133,7 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void NativeWindowImpl_Linux_xcb::Deactivate()
|
||||
void XcbNativeWindow::Deactivate()
|
||||
{
|
||||
if (m_activated) // nothing to do if window was already deactivated
|
||||
{
|
||||
@@ -148,17 +144,17 @@ namespace AzFramework
|
||||
xcb_unmap_window(m_xcbConnection, m_xcbWindow);
|
||||
xcb_flush(m_xcbConnection);
|
||||
}
|
||||
LinuxXcbEventHandlerBus::Handler::BusDisconnect();
|
||||
XcbEventHandlerBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
NativeWindowHandle NativeWindowImpl_Linux_xcb::GetWindowHandle() const
|
||||
NativeWindowHandle XcbNativeWindow::GetWindowHandle() const
|
||||
{
|
||||
return reinterpret_cast<NativeWindowHandle>(m_xcbWindow);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void NativeWindowImpl_Linux_xcb::SetWindowTitle(const AZStd::string& title)
|
||||
void XcbNativeWindow::SetWindowTitle(const AZStd::string& title)
|
||||
{
|
||||
xcb_void_cookie_t xcbCheckResult;
|
||||
xcbCheckResult = xcb_change_property(m_xcbConnection,
|
||||
@@ -173,7 +169,7 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void NativeWindowImpl_Linux_xcb::ResizeClientArea(WindowSize clientAreaSize)
|
||||
void XcbNativeWindow::ResizeClientArea(WindowSize clientAreaSize)
|
||||
{
|
||||
const uint32_t values[] = { clientAreaSize.m_width, clientAreaSize.m_height };
|
||||
|
||||
@@ -184,7 +180,7 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
uint32_t NativeWindowImpl_Linux_xcb::GetDisplayRefreshRate() const
|
||||
uint32_t XcbNativeWindow::GetDisplayRefreshRate() const
|
||||
{
|
||||
// [GFX TODO][GHI - 2678]
|
||||
// Using 60 for now until proper support is added
|
||||
@@ -192,7 +188,7 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool NativeWindowImpl_Linux_xcb::ValidateXcbResult(xcb_void_cookie_t cookie)
|
||||
bool XcbNativeWindow::ValidateXcbResult(xcb_void_cookie_t cookie)
|
||||
{
|
||||
bool result = true;
|
||||
if (xcb_generic_error_t* error = xcb_request_check(m_xcbConnection, cookie))
|
||||
@@ -204,7 +200,7 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void NativeWindowImpl_Linux_xcb::HandleXcbEvent(xcb_generic_event_t* event)
|
||||
void XcbNativeWindow::HandleXcbEvent(xcb_generic_event_t* event)
|
||||
{
|
||||
switch (event->response_type & s_XcbResponseTypeMask)
|
||||
{
|
||||
@@ -233,7 +229,7 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void NativeWindowImpl_Linux_xcb::WindowSizeChanged(const uint32_t width, const uint32_t height)
|
||||
void XcbNativeWindow::WindowSizeChanged(const uint32_t width, const uint32_t height)
|
||||
{
|
||||
if (m_width != width || m_height != height)
|
||||
{
|
||||
@@ -246,7 +242,4 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
|
||||
} // namespace AzFramework
|
||||
+9
-10
@@ -5,24 +5,25 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI_Platform.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzFramework/Windowing/NativeWindow.h>
|
||||
#include <AzFramework/XcbEventHandler.h>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
class NativeWindowImpl_Linux_xcb final
|
||||
class XcbNativeWindow final
|
||||
: public NativeWindow::Implementation
|
||||
, public LinuxXcbEventHandlerBus::Handler
|
||||
, public XcbEventHandlerBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(NativeWindowImpl_Linux_xcb, AZ::SystemAllocator, 0);
|
||||
NativeWindowImpl_Linux_xcb();
|
||||
~NativeWindowImpl_Linux_xcb() override;
|
||||
AZ_CLASS_ALLOCATOR(XcbNativeWindow, AZ::SystemAllocator, 0);
|
||||
XcbNativeWindow();
|
||||
~XcbNativeWindow() override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NativeWindow::Implementation
|
||||
@@ -37,7 +38,7 @@ namespace AzFramework
|
||||
uint32_t GetDisplayRefreshRate() const override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// LinuxXcbEventHandlerBus::Handler
|
||||
// XcbEventHandlerBus::Handler
|
||||
void HandleXcbEvent(xcb_generic_event_t* event) override;
|
||||
|
||||
private:
|
||||
@@ -49,6 +50,4 @@ namespace AzFramework
|
||||
xcb_atom_t m_xcbAtomProtocols;
|
||||
xcb_atom_t m_xcbAtomDeleteWindow;
|
||||
};
|
||||
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
set(FILES
|
||||
AzFramework/XcbApplication.cpp
|
||||
AzFramework/XcbApplication.h
|
||||
AzFramework/XcbConnectionManager.h
|
||||
AzFramework/XcbInputDeviceKeyboard.cpp
|
||||
AzFramework/XcbInputDeviceKeyboard.h
|
||||
AzFramework/XcbInterface.h
|
||||
AzFramework/XcbNativeWindow.cpp
|
||||
AzFramework/XcbNativeWindow.h
|
||||
)
|
||||
@@ -12,10 +12,6 @@
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
#include <xcb/xcb.h>
|
||||
#endif // LY_COMPILE_DEFINITIONS
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class LinuxLifecycleEvents
|
||||
@@ -30,54 +26,4 @@ namespace AzFramework
|
||||
|
||||
using Bus = AZ::EBus<LinuxLifecycleEvents>;
|
||||
};
|
||||
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
class LinuxXcbConnectionManager
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(LinuxXcbConnectionManager, "{1F756E14-8D74-42FD-843C-4863307710DB}");
|
||||
|
||||
virtual ~LinuxXcbConnectionManager() = default;
|
||||
|
||||
virtual xcb_connection_t* GetXcbConnection() const = 0;
|
||||
};
|
||||
|
||||
class LinuxXcbConnectionManagerBusTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
|
||||
using LinuxXcbConnectionManagerBus = AZ::EBus<LinuxXcbConnectionManager, LinuxXcbConnectionManagerBusTraits>;
|
||||
using LinuxXcbConnectionManagerInterface = AZ::Interface<LinuxXcbConnectionManager>;
|
||||
|
||||
class LinuxXcbEventHandler
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(LinuxXcbEventHandler, "{3F756E14-8D74-42FD-843C-4863307710DB}");
|
||||
|
||||
virtual ~LinuxXcbEventHandler() = default;
|
||||
|
||||
virtual void HandleXcbEvent(xcb_generic_event_t* event) = 0;
|
||||
};
|
||||
|
||||
class LinuxXcbEventHandlerBusTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
|
||||
using LinuxXcbEventHandlerBus = AZ::EBus<LinuxXcbEventHandler, LinuxXcbEventHandlerBusTraits>;
|
||||
|
||||
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
} // namespace AzFramework
|
||||
|
||||
+4
-2
@@ -8,7 +8,9 @@
|
||||
|
||||
#include <AzFramework/Application/Application.h>
|
||||
|
||||
#include "Application_Linux_xcb.h"
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
#include <AzFramework/XcbApplication.h>
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
namespace AzFramework
|
||||
@@ -17,7 +19,7 @@ namespace AzFramework
|
||||
Application::Implementation* Application::Implementation::Create()
|
||||
{
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
return aznew ApplicationLinux_xcb();
|
||||
return aznew XcbApplication();
|
||||
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
|
||||
#error "Linux Window Manager Wayland not supported."
|
||||
return nullptr;
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
#include <AzFramework/XcbInputDeviceKeyboard.h>
|
||||
#endif
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
InputDeviceKeyboard::Implementation* InputDeviceKeyboard::Implementation::Create(InputDeviceKeyboard& inputDevice)
|
||||
{
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
return aznew XcbInputDeviceKeyboard(inputDevice);
|
||||
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
|
||||
#error "Linux Window Manager Wayland not supported."
|
||||
return nullptr;
|
||||
#else
|
||||
#error "Linux Window Manager not recognized."
|
||||
return nullptr;
|
||||
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
}
|
||||
} // namespace AzFramework
|
||||
-293
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/std/typetraits/integral_constant.h>
|
||||
#include <AzFramework/API/ApplicationAPI_Linux.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
|
||||
#define explicit ExplicitIsACXXKeyword
|
||||
#include <xcb/xkb.h>
|
||||
#undef explicit
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-x11.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class InputDeviceKeyboardXcb
|
||||
: public InputDeviceKeyboard::Implementation
|
||||
, public LinuxXcbEventHandlerBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(InputDeviceKeyboardXcb, AZ::SystemAllocator, 0);
|
||||
|
||||
using InputDeviceKeyboard::Implementation::Implementation;
|
||||
InputDeviceKeyboardXcb(InputDeviceKeyboard& inputDevice)
|
||||
: InputDeviceKeyboard::Implementation(inputDevice)
|
||||
{
|
||||
LinuxXcbEventHandlerBus::Handler::BusConnect();
|
||||
|
||||
auto* interface = AzFramework::LinuxXcbConnectionManagerInterface::Get();
|
||||
if (!interface)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "XCB interface not available");
|
||||
return;
|
||||
}
|
||||
|
||||
auto* connection = AzFramework::LinuxXcbConnectionManagerInterface::Get()->GetXcbConnection();
|
||||
if (!connection)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "XCB connection not available");
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<xcb_xkb_use_extension_reply_t, DeleterForFreeFn<::std::free>> xkbUseExtensionReply{
|
||||
xcb_xkb_use_extension_reply(connection, xcb_xkb_use_extension(connection, 1, 0), nullptr)
|
||||
};
|
||||
if (!xkbUseExtensionReply)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "Failed to initialize the xkb extension");
|
||||
return;
|
||||
}
|
||||
if (!xkbUseExtensionReply->supported)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "The X server does not support the xkb extension");
|
||||
return;
|
||||
}
|
||||
|
||||
m_coreDeviceId = xkb_x11_get_core_keyboard_device_id(connection);
|
||||
|
||||
m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
|
||||
m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), connection, m_coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS));
|
||||
m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), connection, m_coreDeviceId));
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
bool IsConnected() const override
|
||||
{
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
bool HasTextEntryStarted() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options) override
|
||||
{
|
||||
}
|
||||
|
||||
void TextEntryStop() override
|
||||
{
|
||||
}
|
||||
|
||||
void TickInputDevice() override
|
||||
{
|
||||
ProcessRawEventQueues();
|
||||
}
|
||||
|
||||
void HandleXcbEvent(xcb_generic_event_t* event) override
|
||||
{
|
||||
if (!IsConnected())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event->response_type & ~0x80)
|
||||
{
|
||||
case XCB_KEY_PRESS:
|
||||
{
|
||||
auto* keyPress = reinterpret_cast<xcb_key_press_event_t*>(event);
|
||||
|
||||
const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail);
|
||||
if (key)
|
||||
{
|
||||
QueueRawKeyEvent(*key, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XCB_KEY_RELEASE:
|
||||
{
|
||||
auto* keyRelease = reinterpret_cast<xcb_key_release_event_t*>(event);
|
||||
|
||||
const InputChannelId* key = InputChannelFromKeyEvent(keyRelease->detail);
|
||||
if (key)
|
||||
{
|
||||
QueueRawKeyEvent(*key, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const
|
||||
{
|
||||
const xcb_keysym_t keysym = xkb_state_key_get_one_sym(m_xkbState.get(), code);
|
||||
|
||||
switch(keysym)
|
||||
{
|
||||
case XKB_KEY_0: return &InputDeviceKeyboard::Key::Alphanumeric0;
|
||||
case XKB_KEY_1: return &InputDeviceKeyboard::Key::Alphanumeric1;
|
||||
case XKB_KEY_2: return &InputDeviceKeyboard::Key::Alphanumeric2;
|
||||
case XKB_KEY_3: return &InputDeviceKeyboard::Key::Alphanumeric3;
|
||||
case XKB_KEY_4: return &InputDeviceKeyboard::Key::Alphanumeric4;
|
||||
case XKB_KEY_5: return &InputDeviceKeyboard::Key::Alphanumeric5;
|
||||
case XKB_KEY_6: return &InputDeviceKeyboard::Key::Alphanumeric6;
|
||||
case XKB_KEY_7: return &InputDeviceKeyboard::Key::Alphanumeric7;
|
||||
case XKB_KEY_8: return &InputDeviceKeyboard::Key::Alphanumeric8;
|
||||
case XKB_KEY_9: return &InputDeviceKeyboard::Key::Alphanumeric9;
|
||||
case XKB_KEY_A:
|
||||
case XKB_KEY_a: return &InputDeviceKeyboard::Key::AlphanumericA;
|
||||
case XKB_KEY_B:
|
||||
case XKB_KEY_b: return &InputDeviceKeyboard::Key::AlphanumericB;
|
||||
case XKB_KEY_C:
|
||||
case XKB_KEY_c: return &InputDeviceKeyboard::Key::AlphanumericC;
|
||||
case XKB_KEY_D:
|
||||
case XKB_KEY_d: return &InputDeviceKeyboard::Key::AlphanumericD;
|
||||
case XKB_KEY_E:
|
||||
case XKB_KEY_e: return &InputDeviceKeyboard::Key::AlphanumericE;
|
||||
case XKB_KEY_F:
|
||||
case XKB_KEY_f: return &InputDeviceKeyboard::Key::AlphanumericF;
|
||||
case XKB_KEY_G:
|
||||
case XKB_KEY_g: return &InputDeviceKeyboard::Key::AlphanumericG;
|
||||
case XKB_KEY_H:
|
||||
case XKB_KEY_h: return &InputDeviceKeyboard::Key::AlphanumericH;
|
||||
case XKB_KEY_I:
|
||||
case XKB_KEY_i: return &InputDeviceKeyboard::Key::AlphanumericI;
|
||||
case XKB_KEY_J:
|
||||
case XKB_KEY_j: return &InputDeviceKeyboard::Key::AlphanumericJ;
|
||||
case XKB_KEY_K:
|
||||
case XKB_KEY_k: return &InputDeviceKeyboard::Key::AlphanumericK;
|
||||
case XKB_KEY_L:
|
||||
case XKB_KEY_l: return &InputDeviceKeyboard::Key::AlphanumericL;
|
||||
case XKB_KEY_M:
|
||||
case XKB_KEY_m: return &InputDeviceKeyboard::Key::AlphanumericM;
|
||||
case XKB_KEY_N:
|
||||
case XKB_KEY_n: return &InputDeviceKeyboard::Key::AlphanumericN;
|
||||
case XKB_KEY_O:
|
||||
case XKB_KEY_o: return &InputDeviceKeyboard::Key::AlphanumericO;
|
||||
case XKB_KEY_P:
|
||||
case XKB_KEY_p: return &InputDeviceKeyboard::Key::AlphanumericP;
|
||||
case XKB_KEY_Q:
|
||||
case XKB_KEY_q: return &InputDeviceKeyboard::Key::AlphanumericQ;
|
||||
case XKB_KEY_R:
|
||||
case XKB_KEY_r: return &InputDeviceKeyboard::Key::AlphanumericR;
|
||||
case XKB_KEY_S:
|
||||
case XKB_KEY_s: return &InputDeviceKeyboard::Key::AlphanumericS;
|
||||
case XKB_KEY_T:
|
||||
case XKB_KEY_t: return &InputDeviceKeyboard::Key::AlphanumericT;
|
||||
case XKB_KEY_U:
|
||||
case XKB_KEY_u: return &InputDeviceKeyboard::Key::AlphanumericU;
|
||||
case XKB_KEY_V:
|
||||
case XKB_KEY_v: return &InputDeviceKeyboard::Key::AlphanumericV;
|
||||
case XKB_KEY_W:
|
||||
case XKB_KEY_w: return &InputDeviceKeyboard::Key::AlphanumericW;
|
||||
case XKB_KEY_X:
|
||||
case XKB_KEY_x: return &InputDeviceKeyboard::Key::AlphanumericX;
|
||||
case XKB_KEY_Y:
|
||||
case XKB_KEY_y: return &InputDeviceKeyboard::Key::AlphanumericY;
|
||||
case XKB_KEY_Z:
|
||||
case XKB_KEY_z: return &InputDeviceKeyboard::Key::AlphanumericZ;
|
||||
case XKB_KEY_BackSpace: return &InputDeviceKeyboard::Key::EditBackspace;
|
||||
case XKB_KEY_Caps_Lock: return &InputDeviceKeyboard::Key::EditCapsLock;
|
||||
case XKB_KEY_Return: return &InputDeviceKeyboard::Key::EditEnter;
|
||||
case XKB_KEY_space: return &InputDeviceKeyboard::Key::EditSpace;
|
||||
case XKB_KEY_Tab: return &InputDeviceKeyboard::Key::EditTab;
|
||||
case XKB_KEY_Escape: return &InputDeviceKeyboard::Key::Escape;
|
||||
case XKB_KEY_F1: return &InputDeviceKeyboard::Key::Function01;
|
||||
case XKB_KEY_F2: return &InputDeviceKeyboard::Key::Function02;
|
||||
case XKB_KEY_F3: return &InputDeviceKeyboard::Key::Function03;
|
||||
case XKB_KEY_F4: return &InputDeviceKeyboard::Key::Function04;
|
||||
case XKB_KEY_F5: return &InputDeviceKeyboard::Key::Function05;
|
||||
case XKB_KEY_F6: return &InputDeviceKeyboard::Key::Function06;
|
||||
case XKB_KEY_F7: return &InputDeviceKeyboard::Key::Function07;
|
||||
case XKB_KEY_F8: return &InputDeviceKeyboard::Key::Function08;
|
||||
case XKB_KEY_F9: return &InputDeviceKeyboard::Key::Function09;
|
||||
case XKB_KEY_F10: return &InputDeviceKeyboard::Key::Function10;
|
||||
case XKB_KEY_F11: return &InputDeviceKeyboard::Key::Function11;
|
||||
case XKB_KEY_F12: return &InputDeviceKeyboard::Key::Function12;
|
||||
case XKB_KEY_F13: return &InputDeviceKeyboard::Key::Function13;
|
||||
case XKB_KEY_F14: return &InputDeviceKeyboard::Key::Function14;
|
||||
case XKB_KEY_F15: return &InputDeviceKeyboard::Key::Function15;
|
||||
case XKB_KEY_F16: return &InputDeviceKeyboard::Key::Function16;
|
||||
case XKB_KEY_F17: return &InputDeviceKeyboard::Key::Function17;
|
||||
case XKB_KEY_F18: return &InputDeviceKeyboard::Key::Function18;
|
||||
case XKB_KEY_F19: return &InputDeviceKeyboard::Key::Function19;
|
||||
case XKB_KEY_F20: return &InputDeviceKeyboard::Key::Function20;
|
||||
case XKB_KEY_Alt_L: return &InputDeviceKeyboard::Key::ModifierAltL;
|
||||
case XKB_KEY_Alt_R: return &InputDeviceKeyboard::Key::ModifierAltR;
|
||||
case XKB_KEY_Control_L: return &InputDeviceKeyboard::Key::ModifierCtrlL;
|
||||
case XKB_KEY_Control_R: return &InputDeviceKeyboard::Key::ModifierCtrlR;
|
||||
case XKB_KEY_Shift_L: return &InputDeviceKeyboard::Key::ModifierShiftL;
|
||||
case XKB_KEY_Shift_R: return &InputDeviceKeyboard::Key::ModifierShiftR;
|
||||
case XKB_KEY_Super_L: return &InputDeviceKeyboard::Key::ModifierSuperL;
|
||||
case XKB_KEY_Super_R: return &InputDeviceKeyboard::Key::ModifierSuperR;
|
||||
case XKB_KEY_Down: return &InputDeviceKeyboard::Key::NavigationArrowDown;
|
||||
case XKB_KEY_Left: return &InputDeviceKeyboard::Key::NavigationArrowLeft;
|
||||
case XKB_KEY_Right: return &InputDeviceKeyboard::Key::NavigationArrowRight;
|
||||
case XKB_KEY_Up: return &InputDeviceKeyboard::Key::NavigationArrowUp;
|
||||
case XKB_KEY_Delete: return &InputDeviceKeyboard::Key::NavigationDelete;
|
||||
case XKB_KEY_End: return &InputDeviceKeyboard::Key::NavigationEnd;
|
||||
case XKB_KEY_Home: return &InputDeviceKeyboard::Key::NavigationHome;
|
||||
case XKB_KEY_Insert: return &InputDeviceKeyboard::Key::NavigationInsert;
|
||||
case XKB_KEY_Page_Down: return &InputDeviceKeyboard::Key::NavigationPageDown;
|
||||
case XKB_KEY_Page_Up: return &InputDeviceKeyboard::Key::NavigationPageUp;
|
||||
case XKB_KEY_Num_Lock: return &InputDeviceKeyboard::Key::NumLock;
|
||||
case XKB_KEY_KP_0: return &InputDeviceKeyboard::Key::NumPad0;
|
||||
case XKB_KEY_KP_1: return &InputDeviceKeyboard::Key::NumPad1;
|
||||
case XKB_KEY_KP_2: return &InputDeviceKeyboard::Key::NumPad2;
|
||||
case XKB_KEY_KP_3: return &InputDeviceKeyboard::Key::NumPad3;
|
||||
case XKB_KEY_KP_4: return &InputDeviceKeyboard::Key::NumPad4;
|
||||
case XKB_KEY_KP_5: return &InputDeviceKeyboard::Key::NumPad5;
|
||||
case XKB_KEY_KP_6: return &InputDeviceKeyboard::Key::NumPad6;
|
||||
case XKB_KEY_KP_7: return &InputDeviceKeyboard::Key::NumPad7;
|
||||
case XKB_KEY_KP_8: return &InputDeviceKeyboard::Key::NumPad8;
|
||||
case XKB_KEY_KP_9: return &InputDeviceKeyboard::Key::NumPad9;
|
||||
case XKB_KEY_KP_Add: return &InputDeviceKeyboard::Key::NumPadAdd;
|
||||
case XKB_KEY_KP_Decimal: return &InputDeviceKeyboard::Key::NumPadDecimal;
|
||||
case XKB_KEY_KP_Divide: return &InputDeviceKeyboard::Key::NumPadDivide;
|
||||
case XKB_KEY_KP_Enter: return &InputDeviceKeyboard::Key::NumPadEnter;
|
||||
case XKB_KEY_KP_Multiply: return &InputDeviceKeyboard::Key::NumPadMultiply;
|
||||
case XKB_KEY_KP_Subtract: return &InputDeviceKeyboard::Key::NumPadSubtract;
|
||||
case XKB_KEY_apostrophe: return &InputDeviceKeyboard::Key::PunctuationApostrophe;
|
||||
case XKB_KEY_backslash: return &InputDeviceKeyboard::Key::PunctuationBackslash;
|
||||
case XKB_KEY_bracketleft: return &InputDeviceKeyboard::Key::PunctuationBracketL;
|
||||
case XKB_KEY_bracketright: return &InputDeviceKeyboard::Key::PunctuationBracketR;
|
||||
case XKB_KEY_comma: return &InputDeviceKeyboard::Key::PunctuationComma;
|
||||
case XKB_KEY_equal: return &InputDeviceKeyboard::Key::PunctuationEquals;
|
||||
case XKB_KEY_hyphen: return &InputDeviceKeyboard::Key::PunctuationHyphen;
|
||||
case XKB_KEY_period: return &InputDeviceKeyboard::Key::PunctuationPeriod;
|
||||
case XKB_KEY_semicolon: return &InputDeviceKeyboard::Key::PunctuationSemicolon;
|
||||
case XKB_KEY_slash: return &InputDeviceKeyboard::Key::PunctuationSlash;
|
||||
case XKB_KEY_grave:
|
||||
case XKB_KEY_asciitilde: return &InputDeviceKeyboard::Key::PunctuationTilde;
|
||||
case XKB_KEY_ISO_Group_Shift: return &InputDeviceKeyboard::Key::SupplementaryISO;
|
||||
case XKB_KEY_Pause: return &InputDeviceKeyboard::Key::WindowsSystemPause;
|
||||
case XKB_KEY_Print: return &InputDeviceKeyboard::Key::WindowsSystemPrint;
|
||||
case XKB_KEY_Scroll_Lock: return &InputDeviceKeyboard::Key::WindowsSystemScrollLock;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<auto freeFn>
|
||||
using DeleterForFreeFn = AZStd::integral_constant<decltype(freeFn), freeFn>;
|
||||
|
||||
AZStd::unique_ptr<xkb_context, DeleterForFreeFn<xkb_context_unref>> m_xkbContext;
|
||||
AZStd::unique_ptr<xkb_keymap, DeleterForFreeFn<xkb_keymap_unref>> m_xkbKeymap;
|
||||
AZStd::unique_ptr<xkb_state, DeleterForFreeFn<xkb_state_unref>> m_xkbState;
|
||||
int m_coreDeviceId{-1};
|
||||
bool m_initialized{false};
|
||||
};
|
||||
|
||||
InputDeviceKeyboard::Implementation* InputDeviceKeyboard::Implementation::Create(InputDeviceKeyboard& inputDevice)
|
||||
{
|
||||
return aznew InputDeviceKeyboardXcb(inputDevice);
|
||||
}
|
||||
} // namespace AzFramework
|
||||
+4
-3
@@ -6,14 +6,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "NativeWindow_Linux_xcb.h"
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
#include <AzFramework/XcbNativeWindow.h>
|
||||
#endif
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
NativeWindow::Implementation* NativeWindow::Implementation::Create()
|
||||
{
|
||||
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
return aznew NativeWindowImpl_Linux_xcb();
|
||||
return aznew XcbNativeWindow();
|
||||
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
|
||||
#error "Linux Window Manager Wayland not supported."
|
||||
return nullptr;
|
||||
@@ -22,5 +24,4 @@ namespace AzFramework
|
||||
return nullptr;
|
||||
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
}
|
||||
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -10,6 +10,14 @@
|
||||
# Only 'xcb' and 'wayland' are recognized
|
||||
if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
|
||||
|
||||
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
|
||||
set(LY_INCLUDE_DIRECTORIES
|
||||
PUBLIC
|
||||
Platform/Common/Xcb
|
||||
)
|
||||
set(LY_FILES_CMAKE
|
||||
Platform/Common/Xcb/azframework_xcb_files.cmake
|
||||
)
|
||||
set(LY_BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
3rdParty::X11::xcb
|
||||
@@ -18,8 +26,6 @@ if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
|
||||
3rdParty::X11::xkbcommon_X11
|
||||
)
|
||||
|
||||
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
|
||||
|
||||
elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland")
|
||||
|
||||
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND)
|
||||
|
||||
@@ -12,8 +12,6 @@ set(FILES
|
||||
AzFramework/API/ApplicationAPI_Platform.h
|
||||
AzFramework/API/ApplicationAPI_Linux.h
|
||||
AzFramework/Application/Application_Linux.cpp
|
||||
AzFramework/Application/Application_Linux_xcb.h
|
||||
AzFramework/Application/Application_Linux_xcb.cpp
|
||||
AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp
|
||||
AzFramework/Process/ProcessWatcher_Linux.cpp
|
||||
AzFramework/Process/ProcessCommon.h
|
||||
@@ -22,10 +20,8 @@ set(FILES
|
||||
../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp
|
||||
../Common/Default/AzFramework/TargetManagement/TargetManagementComponent_Default.cpp
|
||||
AzFramework/Windowing/NativeWindow_Linux.cpp
|
||||
AzFramework/Windowing/NativeWindow_Linux_xcb.h
|
||||
AzFramework/Windowing/NativeWindow_Linux_xcb.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad_Unimplemented.cpp
|
||||
AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.cpp
|
||||
AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Motion/InputDeviceMotion_Unimplemented.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Unimplemented.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Touch/InputDeviceTouch_Unimplemented.cpp
|
||||
|
||||
+7
-1
@@ -138,7 +138,13 @@ namespace AzToolsFramework
|
||||
m_indexMap[row] = index;
|
||||
m_rowMap[index] = row;
|
||||
++row;
|
||||
++m_displayedItemsCounter;
|
||||
|
||||
// We only want to increase the displayed counter if it is a parent (Source)
|
||||
// so we don't cut children entries.
|
||||
if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source)
|
||||
{
|
||||
++m_displayedItemsCounter;
|
||||
}
|
||||
}
|
||||
|
||||
if (model->hasChildren(index))
|
||||
|
||||
+10
@@ -151,6 +151,10 @@ namespace AzToolsFramework
|
||||
m_ui->m_assetBrowserTableViewWidget, &AssetBrowserTableView::ClearTypeFilter, m_ui->m_searchWidget,
|
||||
&SearchWidget::ClearTypeFilter);
|
||||
|
||||
connect(
|
||||
this, &AssetPickerDialog::SizeChangedSignal, m_ui->m_assetBrowserTableViewWidget,
|
||||
&AssetBrowserTableView::UpdateSizeSlot);
|
||||
|
||||
m_ui->m_assetBrowserTableViewWidget->SetName("AssetBrowserTableView_main");
|
||||
m_tableModel->UpdateTableModelMaps();
|
||||
}
|
||||
@@ -206,6 +210,12 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void AssetPickerDialog::resizeEvent(QResizeEvent* resizeEvent)
|
||||
{
|
||||
emit SizeChangedSignal(m_ui->verticalLayout_4->geometry().width());
|
||||
QDialog::resizeEvent(resizeEvent);
|
||||
}
|
||||
|
||||
void AssetPickerDialog::keyPressEvent(QKeyEvent* e)
|
||||
{
|
||||
// Until search widget is revised, Return key should not close the dialog,
|
||||
|
||||
+4
@@ -46,6 +46,9 @@ namespace AzToolsFramework
|
||||
explicit AssetPickerDialog(AssetSelectionModel& selection, QWidget* parent = nullptr);
|
||||
virtual ~AssetPickerDialog();
|
||||
|
||||
Q_SIGNALS:
|
||||
void SizeChangedSignal(int newWidth);
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// QDialog
|
||||
@@ -53,6 +56,7 @@ namespace AzToolsFramework
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
void keyPressEvent(QKeyEvent* e) override;
|
||||
void resizeEvent(QResizeEvent* resizeEvent) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void DoubleClickedSlot(const QModelIndex& index);
|
||||
|
||||
+3
-3
@@ -117,6 +117,9 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="AzToolsFramework::AssetBrowser::AssetBrowserTableView" name="m_assetBrowserTableViewWidget"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzToolsFramework::AssetBrowser::AssetBrowserTreeView" name="m_assetBrowserTreeViewWidget">
|
||||
<property name="sizePolicy">
|
||||
@@ -142,9 +145,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzToolsFramework::AssetBrowser::AssetBrowserTableView" name="m_assetBrowserTableViewWidget"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
|
||||
+24
-7
@@ -20,29 +20,33 @@ AZ_PUSH_DISABLE_WARNING(
|
||||
#include <QCoreApplication>
|
||||
#include <QHeaderView>
|
||||
#include <QMenu>
|
||||
|
||||
#include <QResizeEvent>
|
||||
#include <QTimer>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
const float MinHeaderResizeProportion = .25f;
|
||||
const float MaxHeaderResizeProportion = .75f;
|
||||
const float DefaultHeaderResizeProportion = .5f;
|
||||
|
||||
AssetBrowserTableView::AssetBrowserTableView(QWidget* parent)
|
||||
: AzQtComponents::TableView(parent)
|
||||
, m_delegate(new EntryDelegate(this))
|
||||
, m_delegate(new SearchEntryDelegate(this))
|
||||
{
|
||||
setSortingEnabled(true);
|
||||
setSortingEnabled(false);
|
||||
setItemDelegate(m_delegate);
|
||||
setRootIsDecorated(false);
|
||||
|
||||
//Styling the header aligning text to the left and using a bold font.
|
||||
header()->setDefaultAlignment(Qt::AlignLeft);
|
||||
header()->setStyleSheet("QHeaderView { font-weight: bold; }");
|
||||
header()->setStyleSheet("QHeaderView { font-weight: bold; };");
|
||||
|
||||
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
setMouseTracking(true);
|
||||
setSortingEnabled(false);
|
||||
setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
connect(this, &AzQtComponents::TableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu);
|
||||
@@ -65,8 +69,12 @@ namespace AzToolsFramework
|
||||
AzQtComponents::TableView::setModel(model);
|
||||
connect(m_tableModel, &AssetBrowserTableModel::layoutChanged, this, &AssetBrowserTableView::layoutChangedSlot);
|
||||
|
||||
header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
|
||||
header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
|
||||
header()->setStretchLastSection(true);
|
||||
header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Interactive);
|
||||
header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Interactive);
|
||||
UpdateSizeSlot(parentWidget()->width());
|
||||
header()->setSortIndicatorShown(false);
|
||||
header()->setSectionsClickable(false);
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::SetName(const QString& name)
|
||||
@@ -146,8 +154,17 @@ namespace AzToolsFramework
|
||||
|
||||
void AssetBrowserTableView::OnAssetBrowserComponentReady()
|
||||
{
|
||||
UpdateSizeSlot(parentWidget()->width());
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::UpdateSizeSlot(int newWidth)
|
||||
{
|
||||
setColumnWidth(0, aznumeric_cast<int>(newWidth * DefaultHeaderResizeProportion));
|
||||
header()->setMinimumSectionSize(aznumeric_cast<int>(newWidth * MinHeaderResizeProportion));
|
||||
header()->setMaximumSectionSize(aznumeric_cast<int>(newWidth * MaxHeaderResizeProportion));
|
||||
}
|
||||
|
||||
|
||||
void AssetBrowserTableView::OnContextMenu([[maybe_unused]] const QPoint& point)
|
||||
{
|
||||
const auto& selectedAssets = GetSelectedAssets();
|
||||
|
||||
+7
-5
@@ -26,7 +26,7 @@ namespace AzToolsFramework
|
||||
class AssetBrowserEntry;
|
||||
class AssetBrowserTableModel;
|
||||
class AssetBrowserFilterModel;
|
||||
class EntryDelegate;
|
||||
class SearchEntryDelegate;
|
||||
|
||||
class AssetBrowserTableView //! Table view that displays the asset browser entries in a list.
|
||||
: public AzQtComponents::TableView
|
||||
@@ -59,17 +59,19 @@ namespace AzToolsFramework
|
||||
void ClearStringFilter();
|
||||
void ClearTypeFilter();
|
||||
|
||||
public Q_SLOTS:
|
||||
void UpdateSizeSlot(int newWidth);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) override;
|
||||
void rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) override;
|
||||
void layoutChangedSlot(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(),
|
||||
QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QPointer<AssetBrowserTableModel> m_tableModel = nullptr;
|
||||
QPointer<AssetBrowserFilterModel> m_sourceFilterModel = nullptr;
|
||||
EntryDelegate* m_delegate = nullptr;
|
||||
QPointer<AssetBrowserTableModel> m_tableModel;
|
||||
QPointer<AssetBrowserFilterModel> m_sourceFilterModel;
|
||||
SearchEntryDelegate* m_delegate = nullptr;
|
||||
|
||||
private Q_SLOTS:
|
||||
void OnContextMenu(const QPoint& point);
|
||||
|
||||
+167
-6
@@ -11,12 +11,13 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Views/EntryDelegate.h>
|
||||
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzQtComponents/Components/StyledBusyLabel.h>
|
||||
|
||||
#include <QApplication>
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer<QBrushData,QBrushDataPointerDeleter>' needs to have dll-interface to be used by clients of class 'QBrush'
|
||||
// 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning)
|
||||
#include <QAbstractItemView>
|
||||
#include <QPainter>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
@@ -24,8 +25,13 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
const int ENTRY_SPACING_LEFT_PIXELS = 8;
|
||||
const int ENTRY_ICON_MARGIN_LEFT_PIXELS = 2;
|
||||
static constexpr const char* TreeIconPathFirst = "Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg";
|
||||
static constexpr const char* TreeIconPathMiddle = "Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg";
|
||||
static constexpr const char* TreeIconPathLast = "Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg";
|
||||
static constexpr const char* TreeIconPathOneChild = "Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg";
|
||||
|
||||
const int EntrySpacingLeftPixels = 8;
|
||||
const int EntryIconMarginLeftPixels = 2;
|
||||
|
||||
EntryDelegate::EntryDelegate(QWidget* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
@@ -62,7 +68,7 @@ namespace AzToolsFramework
|
||||
|
||||
// Draw main entry thumbnail.
|
||||
QRect remainingRect(option.rect);
|
||||
remainingRect.adjust(ENTRY_ICON_MARGIN_LEFT_PIXELS, 0, 0, 0); // bump it rightwards to give some margin to the icon.
|
||||
remainingRect.adjust(EntryIconMarginLeftPixels, 0, 0, 0); // bump it rightwards to give some margin to the icon.
|
||||
|
||||
QSize iconSize(m_iconSize, m_iconSize);
|
||||
// Note that the thumbnail might actually be smaller than the row if theres a lot of padding or font size
|
||||
@@ -89,7 +95,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
remainingRect.adjust(thumbX, 0, 0, 0); // bump it to the right by the size of the thumbnail
|
||||
remainingRect.adjust(ENTRY_SPACING_LEFT_PIXELS, 0, 0, 0); // bump it to the right by the spacing.
|
||||
remainingRect.adjust(EntrySpacingLeftPixels, 0, 0, 0); // bump it to the right by the spacing.
|
||||
}
|
||||
QString displayString = index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name)
|
||||
? qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Name)))
|
||||
@@ -148,7 +154,162 @@ namespace AzToolsFramework
|
||||
return m_iconSize;
|
||||
}
|
||||
|
||||
} // namespace Thumbnailer
|
||||
SearchEntryDelegate::SearchEntryDelegate(QWidget* parent)
|
||||
: EntryDelegate(parent)
|
||||
{
|
||||
LoadBranchPixMaps();
|
||||
}
|
||||
|
||||
void SearchEntryDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
auto data = index.data(AssetBrowserModel::Roles::EntryRole);
|
||||
if (data.canConvert<const AssetBrowserEntry*>())
|
||||
{
|
||||
bool isEnabled = (option.state & QStyle::State_Enabled) != 0;
|
||||
bool isSelected = (option.state & QStyle::State_Selected) != 0;
|
||||
|
||||
QStyle* style = option.widget ? option.widget->style() : QApplication::style();
|
||||
|
||||
// draw the background
|
||||
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, option.widget);
|
||||
|
||||
// Draw main entry thumbnail.
|
||||
QRect remainingRect(option.rect);
|
||||
|
||||
QSize iconSize(m_iconSize, m_iconSize);
|
||||
// Note that the thumbnail might actually be smaller than the row if theres a lot of padding or font size
|
||||
// so it needs to center vertically with padding in that case:
|
||||
QPoint iconTopLeft;
|
||||
QPoint branchIconTopLeft = QPoint();
|
||||
|
||||
auto entry = qvariant_cast<const AssetBrowserEntry*>(data);
|
||||
auto sourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(entry);
|
||||
|
||||
//If it is a SourceEntry or it is not the column name we don't want to add space for the branch Icon
|
||||
if (sourceEntry || index.column() != aznumeric_cast<int>(AssetBrowserEntry::Column::Name))
|
||||
{
|
||||
remainingRect.adjust(EntryIconMarginLeftPixels, 0, 0, 0); // bump it rightwards to give some margin to the icon.
|
||||
iconTopLeft = QPoint(remainingRect.x(), remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
remainingRect.adjust(EntryIconMarginLeftPixels + m_iconSize, 0, 0, 0); // bump it rightwards to give some margin to the icon.
|
||||
iconTopLeft = QPoint(remainingRect.x() / 2 + m_iconSize, remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
|
||||
branchIconTopLeft = QPoint((remainingRect.x() / 2) - 2, remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
|
||||
}
|
||||
|
||||
QPalette actualPalette(option.palette);
|
||||
|
||||
if (index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name))
|
||||
{
|
||||
int thumbX = DrawThumbnail(painter, iconTopLeft, iconSize, entry->GetThumbnailKey());
|
||||
if (sourceEntry)
|
||||
{
|
||||
if (m_showSourceControl)
|
||||
{
|
||||
DrawThumbnail(painter, iconTopLeft, iconSize, sourceEntry->GetSourceControlThumbnailKey());
|
||||
}
|
||||
// sources with no children should be greyed out.
|
||||
if (sourceEntry->GetChildCount() == 0)
|
||||
{
|
||||
isEnabled = false; // draw in disabled style.
|
||||
actualPalette.setCurrentColorGroup(QPalette::Disabled);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Get the indexes above and below our entry to see what type are they.
|
||||
QAbstractItemView* view = qobject_cast<QAbstractItemView*>(option.styleObject);
|
||||
const QAbstractItemModel* viewModel = view->model();
|
||||
|
||||
const QModelIndex indexBelow = viewModel->index(index.row() + 1, index.column());
|
||||
const QModelIndex indexAbove = viewModel->index(index.row() - 1, index.column());
|
||||
|
||||
auto aboveEntry = qvariant_cast<const AssetBrowserEntry*>(indexBelow.data(AssetBrowserModel::Roles::EntryRole));
|
||||
auto belowEntry = qvariant_cast<const AssetBrowserEntry*>(indexAbove.data(AssetBrowserModel::Roles::EntryRole));
|
||||
|
||||
auto aboveSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(aboveEntry);
|
||||
auto belowSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(belowEntry);
|
||||
|
||||
// if current index is the last entry in the view
|
||||
// or the index above it is a Source Entry and
|
||||
// the index below is invalid or is valid but it is also a source entry
|
||||
// then the current index is the only child.
|
||||
if (index.row() == viewModel->rowCount() - 1 ||
|
||||
(indexBelow.isValid() && aboveSourceEntry &&
|
||||
(!indexAbove.isValid() || (indexAbove.isValid() && belowSourceEntry))))
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::OneChild, painter, branchIconTopLeft, iconSize); // Draw One Child Icon
|
||||
}
|
||||
else if (indexBelow.isValid() && aboveSourceEntry) // The index above is a source entry
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::Last, painter, branchIconTopLeft, iconSize); // Draw First child Icon
|
||||
}
|
||||
else if (indexAbove.isValid() && belowSourceEntry) // The index below is a source entry
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::First, painter, branchIconTopLeft, iconSize); // Draw Last Child Icon
|
||||
}
|
||||
else //the index above and below are also child entries
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::Middle, painter, branchIconTopLeft, iconSize); // Draw Default child Icon.
|
||||
}
|
||||
}
|
||||
|
||||
remainingRect.adjust(thumbX, 0, 0, 0); // bump it to the right by the size of the thumbnail
|
||||
remainingRect.adjust(EntrySpacingLeftPixels, 0, 0, 0); // bump it to the right by the spacing.
|
||||
}
|
||||
QString displayString = index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name)
|
||||
? qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Name)))
|
||||
: qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Path)));
|
||||
|
||||
style->drawItemText(
|
||||
painter, remainingRect, option.displayAlignment, actualPalette, isEnabled, displayString,
|
||||
isSelected ? QPalette::HighlightedText : QPalette::Text);
|
||||
}
|
||||
}
|
||||
|
||||
void SearchEntryDelegate::LoadBranchPixMaps()
|
||||
{
|
||||
AZ::IO::BasicPath<AZ::IO::FixedMaxPathString> absoluteIconPath;
|
||||
for (int branchType = EntryBranchType::First; branchType != EntryBranchType::Count; ++branchType)
|
||||
{
|
||||
QPixmap pixmap;
|
||||
switch (branchType)
|
||||
{
|
||||
case AzToolsFramework::AssetBrowser::EntryBranchType::First:
|
||||
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathFirst;
|
||||
break;
|
||||
case AzToolsFramework::AssetBrowser::EntryBranchType::Middle:
|
||||
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathMiddle;
|
||||
break;
|
||||
case AzToolsFramework::AssetBrowser::EntryBranchType::Last:
|
||||
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathLast;
|
||||
break;
|
||||
case AzToolsFramework::AssetBrowser::EntryBranchType::OneChild:
|
||||
default:
|
||||
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathOneChild;
|
||||
break;
|
||||
}
|
||||
bool pixmapLoadedSuccess = pixmap.load(absoluteIconPath.c_str());
|
||||
AZ_Assert(pixmapLoadedSuccess, "Error loading Branch Icons in SearchEntryDelegate");
|
||||
|
||||
m_branchIcons[static_cast<EntryBranchType>(branchType)] = pixmap;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SearchEntryDelegate::DrawBranchPixMap(
|
||||
EntryBranchType branchType, QPainter* painter, const QPoint& point, const QSize& size) const
|
||||
{
|
||||
const QPixmap& pixmap = m_branchIcons[branchType];
|
||||
|
||||
pixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
const QSize sizeDelta = size - pixmap.size();
|
||||
const QPoint pointDelta = QPoint(sizeDelta.width() / 2, sizeDelta.height() / 2);
|
||||
painter->drawPixmap(point + pointDelta, pixmap);
|
||||
}
|
||||
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
#include "AssetBrowser/Views/moc_EntryDelegate.cpp"
|
||||
|
||||
+29
-1
@@ -27,9 +27,19 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
//! Type of branch icon the delegate should paint.
|
||||
enum EntryBranchType
|
||||
{
|
||||
First,
|
||||
Middle,
|
||||
Last,
|
||||
OneChild,
|
||||
Count
|
||||
};
|
||||
|
||||
class AssetBrowserFilterModel;
|
||||
|
||||
//! EntryDelegate draws a single item in AssetBrowser
|
||||
//! EntryDelegate draws a single item in AssetBrowser.
|
||||
class EntryDelegate
|
||||
: public QStyledItemDelegate
|
||||
{
|
||||
@@ -52,5 +62,23 @@ namespace AzToolsFramework
|
||||
//! Draw a thumbnail and return its width
|
||||
int DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const;
|
||||
};
|
||||
|
||||
//! SearchEntryDelegate draws a single item in AssetBrowserTableView.
|
||||
class SearchEntryDelegate
|
||||
: public EntryDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SearchEntryDelegate(QWidget* parent = nullptr);
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
|
||||
private:
|
||||
void LoadBranchPixMaps();
|
||||
void DrawBranchPixMap(EntryBranchType branchType, QPainter* painter, const QPoint& point, const QSize& size) const;
|
||||
|
||||
private:
|
||||
QMap<EntryBranchType, QPixmap> m_branchIcons;
|
||||
};
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace AzToolsFramework
|
||||
virtual AZ::EntityId GetFocusRoot() = 0;
|
||||
|
||||
//! Returns whether the entity id provided is part of the focused sub-tree.
|
||||
virtual bool IsInFocusSubTree(AZ::EntityId entityId) = 0;
|
||||
virtual bool IsInFocusSubTree(AZ::EntityId entityId) const = 0;
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ namespace AzToolsFramework
|
||||
return m_focusRoot;
|
||||
}
|
||||
|
||||
bool FocusModeSystemComponent::IsInFocusSubTree(AZ::EntityId entityId)
|
||||
bool FocusModeSystemComponent::IsInFocusSubTree(AZ::EntityId entityId) const
|
||||
{
|
||||
if (m_focusRoot == AZ::EntityId())
|
||||
{
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ namespace AzToolsFramework
|
||||
void SetFocusRoot(AZ::EntityId entityId) override;
|
||||
void ClearFocusRoot() override;
|
||||
AZ::EntityId GetFocusRoot() override;
|
||||
bool IsInFocusSubTree(AZ::EntityId entityId) override;
|
||||
bool IsInFocusSubTree(AZ::EntityId entityId) const override;
|
||||
|
||||
private:
|
||||
AZ::EntityId m_focusRoot;
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
m_uniformScaleManipulator->SetVisualOrientationOverride(QuaternionFromTransformNoScaling(localTransform));
|
||||
m_uniformScaleManipulator->SetLocalPosition(localTransform.GetTranslation());
|
||||
m_uniformScaleManipulator->SetLocalOrientation(AZ::Quaternion::CreateIdentity());
|
||||
}
|
||||
|
||||
|
||||
+14
-13
@@ -13,14 +13,14 @@
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
static const float s_surfaceManipulatorTransparency = 0.75f;
|
||||
static const float s_axisLength = 2.0f;
|
||||
static const float s_surfaceManipulatorRadius = 0.1f;
|
||||
static const float SurfaceManipulatorTransparency = 0.75f;
|
||||
static const float LinearManipulatorAxisLength = 2.0f;
|
||||
static const float SurfaceManipulatorRadius = 0.1f;
|
||||
|
||||
static const AZ::Color s_xAxisColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
static const AZ::Color s_yAxisColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
static const AZ::Color s_zAxisColor = AZ::Color(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
static const AZ::Color s_surfaceManipulatorColor = AZ::Color(1.0f, 1.0f, 0.0f, 0.5f);
|
||||
static const AZ::Color LinearManipulatorXAxisColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
static const AZ::Color LinearManipulatorYAxisColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
static const AZ::Color LinearManipulatorZAxisColor = AZ::Color(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
static const AZ::Color SurfaceManipulatorColor = AZ::Color(1.0f, 1.0f, 0.0f, 0.5f);
|
||||
|
||||
TranslationManipulators::TranslationManipulators(
|
||||
const Dimensions dimensions, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale)
|
||||
@@ -291,7 +291,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
const AZ::Color color[2] = {
|
||||
defaultColor,
|
||||
Vector3ToVector4(BaseManipulator::s_defaultMouseOverColor.GetAsVector3(), s_surfaceManipulatorTransparency)
|
||||
Vector3ToVector4(BaseManipulator::s_defaultMouseOverColor.GetAsVector3(), SurfaceManipulatorTransparency)
|
||||
};
|
||||
|
||||
return color[mouseOver];
|
||||
@@ -325,15 +325,16 @@ namespace AzToolsFramework
|
||||
void ConfigureTranslationManipulatorAppearance3d(TranslationManipulators* translationManipulators)
|
||||
{
|
||||
translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
|
||||
translationManipulators->ConfigurePlanarView(s_xAxisColor, s_yAxisColor, s_zAxisColor);
|
||||
translationManipulators->ConfigureLinearView(s_axisLength, s_xAxisColor, s_yAxisColor, s_zAxisColor);
|
||||
translationManipulators->ConfigureSurfaceView(s_surfaceManipulatorRadius, s_surfaceManipulatorColor);
|
||||
translationManipulators->ConfigurePlanarView(LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor);
|
||||
translationManipulators->ConfigureLinearView(
|
||||
LinearManipulatorAxisLength, LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor);
|
||||
translationManipulators->ConfigureSurfaceView(SurfaceManipulatorRadius, SurfaceManipulatorColor);
|
||||
}
|
||||
|
||||
void ConfigureTranslationManipulatorAppearance2d(TranslationManipulators* translationManipulators)
|
||||
{
|
||||
translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY());
|
||||
translationManipulators->ConfigurePlanarView(s_xAxisColor);
|
||||
translationManipulators->ConfigureLinearView(s_axisLength, s_xAxisColor, s_yAxisColor);
|
||||
translationManipulators->ConfigurePlanarView(LinearManipulatorXAxisColor);
|
||||
translationManipulators->ConfigureLinearView(LinearManipulatorAxisLength, LinearManipulatorXAxisColor, LinearManipulatorYAxisColor);
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace AzToolsFramework::Prefab
|
||||
{
|
||||
InstanceOptionalReference focusedInstance;
|
||||
|
||||
if (entityId == AZ::EntityId())
|
||||
if (!entityId.IsValid())
|
||||
{
|
||||
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
|
||||
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
|
||||
@@ -83,7 +83,13 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
bool PrefabFocusHandler::IsOwningPrefabBeingFocused(AZ::EntityId entityId)
|
||||
{
|
||||
if (entityId == AZ::EntityId())
|
||||
if (!m_focusedInstance.has_value())
|
||||
{
|
||||
// PrefabFocusHandler has not been initialized yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!entityId.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -18,18 +18,19 @@ AzToolsFramework--EntityOutlinerWidget QTreeView
|
||||
selection-background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Entity Outliner handles hover and selected state of items via code,
|
||||
* so we need to override the AzQtComponents::Treeview style.
|
||||
*/
|
||||
AzToolsFramework--EntityOutlinerWidget QTreeView::branch:hover
|
||||
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:hover
|
||||
{
|
||||
background: rgba(255, 255, 255, 30);
|
||||
}
|
||||
|
||||
AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected
|
||||
, AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected
|
||||
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:selected
|
||||
, AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected:active
|
||||
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:selected:active
|
||||
{
|
||||
background: rgba(255, 255, 255, 45);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+18
-8
@@ -44,6 +44,7 @@
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/ComponentAssetMimeDataContainer.h>
|
||||
#include <AzToolsFramework/ToolsComponents/ComponentMimeData.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorEntityIdContainer.h>
|
||||
@@ -102,10 +103,14 @@ namespace AzToolsFramework
|
||||
EntityCompositionNotificationBus::Handler::BusConnect();
|
||||
AZ::EntitySystemBus::Handler::BusConnect();
|
||||
|
||||
m_editorEntityFrameworkInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get();
|
||||
m_editorEntityUiInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get();
|
||||
AZ_Assert(m_editorEntityUiInterface != nullptr,
|
||||
"EntityOutlinerListModel requires a EditorEntityUiInterface instance on Initialize.");
|
||||
|
||||
AZ_Assert(m_editorEntityFrameworkInterface != nullptr,
|
||||
"EntityOutlinerListModel requires a EditorEntityFrameworkInterface instance on Initialize.");
|
||||
m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
AZ_Assert(
|
||||
m_focusModeInterface != nullptr,
|
||||
"EntityOutlinerListModel requires a FocusModeInterface instance on Initialize.");
|
||||
}
|
||||
|
||||
int EntityOutlinerListModel::rowCount(const QModelIndex& parent) const
|
||||
@@ -279,7 +284,7 @@ namespace AzToolsFramework
|
||||
|
||||
QVariant EntityOutlinerListModel::GetEntityIcon(const AZ::EntityId& id) const
|
||||
{
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(id);
|
||||
auto entityUiHandler = m_editorEntityUiInterface->GetHandler(id);
|
||||
QIcon icon;
|
||||
|
||||
// Retrieve the icon from the handler
|
||||
@@ -316,7 +321,7 @@ namespace AzToolsFramework
|
||||
|
||||
QVariant EntityOutlinerListModel::GetEntityTooltip(const AZ::EntityId& id) const
|
||||
{
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(id);
|
||||
auto entityUiHandler = m_editorEntityUiInterface->GetHandler(id);
|
||||
QString tooltip;
|
||||
|
||||
// Retrieve the tooltip from the handler
|
||||
@@ -349,7 +354,7 @@ namespace AzToolsFramework
|
||||
QVariant EntityOutlinerListModel::dataForVisibility(const QModelIndex& index, int role) const
|
||||
{
|
||||
auto entityId = GetEntityFromIndex(index);
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId);
|
||||
auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
|
||||
|
||||
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
|
||||
{
|
||||
@@ -377,7 +382,7 @@ namespace AzToolsFramework
|
||||
QVariant EntityOutlinerListModel::dataForLock(const QModelIndex& index, int role) const
|
||||
{
|
||||
auto entityId = GetEntityFromIndex(index);
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId);
|
||||
auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
|
||||
|
||||
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
|
||||
{
|
||||
@@ -436,7 +441,7 @@ namespace AzToolsFramework
|
||||
if (value.canConvert<Qt::CheckState>())
|
||||
{
|
||||
const auto entityId = GetEntityFromIndex(index);
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId);
|
||||
auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
|
||||
|
||||
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
|
||||
{
|
||||
@@ -532,6 +537,11 @@ namespace AzToolsFramework
|
||||
break;
|
||||
}
|
||||
|
||||
if (AZ::EntityId entityId = GetEntityFromIndex(index); !m_focusModeInterface->IsInFocusSubTree(entityId))
|
||||
{
|
||||
itemFlags &= !Qt::ItemIsEnabled;
|
||||
}
|
||||
|
||||
return itemFlags;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -36,6 +36,7 @@
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class EditorEntityUiInterface;
|
||||
class FocusModeInterface;
|
||||
|
||||
namespace EntityOutliner
|
||||
{
|
||||
@@ -273,7 +274,8 @@ namespace AzToolsFramework
|
||||
QVariant GetEntityIcon(const AZ::EntityId& id) const;
|
||||
QVariant GetEntityTooltip(const AZ::EntityId& id) const;
|
||||
|
||||
EditorEntityUiInterface* m_editorEntityFrameworkInterface = nullptr;
|
||||
EditorEntityUiInterface* m_editorEntityUiInterface = nullptr;
|
||||
FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
};
|
||||
|
||||
class EntityOutlinerCheckBox
|
||||
|
||||
+42
@@ -38,6 +38,8 @@ namespace AzToolsFramework
|
||||
|
||||
AZ_Assert((m_editorEntityFrameworkInterface != nullptr),
|
||||
"EntityOutlinerTreeView requires a EditorEntityFrameworkInterface instance on Construction.");
|
||||
|
||||
viewport()->setMouseTracking(true);
|
||||
}
|
||||
|
||||
EntityOutlinerTreeView::~EntityOutlinerTreeView()
|
||||
@@ -59,6 +61,11 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::leaveEvent([[maybe_unused]] QEvent* event)
|
||||
{
|
||||
m_mousePosition = QPoint();
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
//postponing normal mouse pressed logic until mouse is released or dragged
|
||||
@@ -112,6 +119,8 @@ namespace AzToolsFramework
|
||||
setSelectionMode(selectionModeBefore);
|
||||
}
|
||||
|
||||
m_mousePosition = event->pos();
|
||||
|
||||
//process mouse movement as normal, potentially triggering drag and drop
|
||||
QTreeView::mouseMoveEvent(event);
|
||||
}
|
||||
@@ -172,12 +181,45 @@ namespace AzToolsFramework
|
||||
|
||||
void EntityOutlinerTreeView::drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const
|
||||
{
|
||||
const bool isEnabled = (this->model()->flags(index) & Qt::ItemIsEnabled);
|
||||
|
||||
const bool isSelected = selectionModel()->isSelected(index);
|
||||
const bool isHovered = (index == indexAt(m_mousePosition)) && isEnabled;
|
||||
|
||||
// Paint the branch Selection/Hover Rect
|
||||
PaintBranchSelectionHoverRect(painter, rect, isSelected, isHovered);
|
||||
|
||||
// Paint the branch background as defined by the entity's handler, or its closes ancestor's.
|
||||
PaintBranchBackground(painter, rect, index);
|
||||
|
||||
QTreeView::drawBranches(painter, rect, index);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::PaintBranchSelectionHoverRect(
|
||||
QPainter* painter, const QRect& rect, bool isSelected, bool isHovered) const
|
||||
{
|
||||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing, false);
|
||||
|
||||
if (isSelected || isHovered)
|
||||
{
|
||||
QPainterPath backgroundPath;
|
||||
QRect backgroundRect(rect);
|
||||
|
||||
backgroundPath.addRect(backgroundRect);
|
||||
|
||||
QColor backgroundColor = m_hoverColor;
|
||||
if (isSelected)
|
||||
{
|
||||
backgroundColor = m_selectedColor;
|
||||
}
|
||||
|
||||
painter->fillPath(backgroundPath, backgroundColor);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const
|
||||
{
|
||||
// Go through ancestors and add them to the stack
|
||||
|
||||
+3
@@ -59,6 +59,7 @@ namespace AzToolsFramework
|
||||
void startDrag(Qt::DropActions supportedActions) override;
|
||||
void dragMoveEvent(QDragMoveEvent* event) override;
|
||||
void dropEvent(QDropEvent* event) override;
|
||||
void leaveEvent(QEvent* event) override;
|
||||
|
||||
//! Renders the left side of the item: appropriate background, branch lines, icons.
|
||||
void drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const override;
|
||||
@@ -72,8 +73,10 @@ namespace AzToolsFramework
|
||||
void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions) override;
|
||||
|
||||
void PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const;
|
||||
void PaintBranchSelectionHoverRect(QPainter* painter, const QRect& rect, bool isSelected, bool isHovered) const;
|
||||
|
||||
QMouseEvent* m_queuedMouseEvent;
|
||||
QPoint m_mousePosition;
|
||||
bool m_draggingUnselectedItem; // This is set when an item is dragged outside its bounding box.
|
||||
|
||||
int m_expandOnlyDelay = -1;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AzFramework/Viewport/ViewportScreen.h>
|
||||
#include <AzFramework/Visibility/BoundsBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/API/EditorViewportIconDisplayInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorEntityIconComponentBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
@@ -112,6 +113,17 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
EditorHelpers::EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache)
|
||||
: m_entityDataCache(entityDataCache)
|
||||
{
|
||||
m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
AZ_Assert(
|
||||
m_focusModeInterface,
|
||||
"EditorHelpers - "
|
||||
"Focus Mode Interface could not be found. "
|
||||
"Check that it is being correctly initialized.");
|
||||
}
|
||||
|
||||
AZ::EntityId EditorHelpers::HandleMouseInteraction(
|
||||
const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
|
||||
{
|
||||
@@ -173,6 +185,12 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
// Verify if the entity Id corresponds to an entity that is focused; if not, halt selection.
|
||||
if (!m_focusModeInterface->IsInFocusSubTree(entityIdUnderCursor))
|
||||
{
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
return entityIdUnderCursor;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace AzFramework
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class EditorVisibleEntityDataCache;
|
||||
class FocusModeInterface;
|
||||
|
||||
namespace ViewportInteraction
|
||||
{
|
||||
@@ -38,10 +39,7 @@ namespace AzToolsFramework
|
||||
|
||||
//! An EditorVisibleEntityDataCache must be passed to EditorHelpers to allow it to
|
||||
//! efficiently read entity data without resorting to EBus calls.
|
||||
explicit EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache)
|
||||
: m_entityDataCache(entityDataCache)
|
||||
{
|
||||
}
|
||||
explicit EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache);
|
||||
EditorHelpers(const EditorHelpers&) = delete;
|
||||
EditorHelpers& operator=(const EditorHelpers&) = delete;
|
||||
~EditorHelpers() = default;
|
||||
@@ -62,5 +60,6 @@ namespace AzToolsFramework
|
||||
|
||||
private:
|
||||
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers.
|
||||
const FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+92
-87
@@ -700,13 +700,6 @@ namespace AzToolsFramework
|
||||
switch (referenceFrame)
|
||||
{
|
||||
case ReferenceFrame::Local:
|
||||
// if we have a group selection, always use the pivot override if one
|
||||
// is set when moving to local space (can't pick individual local space)
|
||||
if (entityIdMap.size() > 1)
|
||||
{
|
||||
pivot.m_worldOrientation = pivotOverrideFrame.m_orientationOverride.value();
|
||||
}
|
||||
break;
|
||||
case ReferenceFrame::Parent:
|
||||
pivot.m_worldOrientation = pivotOverrideFrame.m_orientationOverride.value();
|
||||
break;
|
||||
@@ -784,7 +777,7 @@ namespace AzToolsFramework
|
||||
SortEntitiesByLocationInHierarchy(sortedEntityIdsOut);
|
||||
}
|
||||
|
||||
static void UpdateInitialRotation(EntityIdManipulators& entityManipulators)
|
||||
static void UpdateInitialTransform(EntityIdManipulators& entityManipulators)
|
||||
{
|
||||
// save new start orientation (if moving rotation axes separate from object
|
||||
// or switching type of rotation (modifier keys change))
|
||||
@@ -797,22 +790,17 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
// utility function to immediately return the current reference frame
|
||||
// based on the state of the modifiers
|
||||
// utility function to immediately return the current reference frame based on the state of the modifiers
|
||||
static ReferenceFrame ReferenceFrameFromModifiers(const ViewportInteraction::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (modifiers.Shift() && !modifiers.Alt())
|
||||
{
|
||||
return ReferenceFrame::World;
|
||||
}
|
||||
else if (modifiers.Alt() && !modifiers.Shift())
|
||||
{
|
||||
return ReferenceFrame::Local;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ReferenceFrame::Parent;
|
||||
}
|
||||
return modifiers.Shift() ? ReferenceFrame::World : ReferenceFrame::Local;
|
||||
}
|
||||
|
||||
// utility function to immediately return the current sphere of influence of the manipulators based on the
|
||||
// state of the modifiers
|
||||
static Influence InfluenceFromModifiers(const ViewportInteraction::KeyboardModifiers modifiers)
|
||||
{
|
||||
return modifiers.Alt() ? Influence::Individual : Influence::Group;
|
||||
}
|
||||
|
||||
template<typename Action, typename EntityIdContainer>
|
||||
@@ -838,6 +826,7 @@ namespace AzToolsFramework
|
||||
else
|
||||
{
|
||||
const ReferenceFrame referenceFrame = spaceLock.value_or(ReferenceFrameFromModifiers(action.m_modifiers));
|
||||
const Influence influence = InfluenceFromModifiers(action.m_modifiers);
|
||||
|
||||
// note: used for parent and world depending on the current reference frame
|
||||
const auto pivotOrientation =
|
||||
@@ -854,9 +843,9 @@ namespace AzToolsFramework
|
||||
|
||||
const AZ::Vector3 worldTranslation = GetWorldTranslation(entityId);
|
||||
|
||||
switch (referenceFrame)
|
||||
switch (influence)
|
||||
{
|
||||
case ReferenceFrame::Local:
|
||||
case Influence::Individual:
|
||||
{
|
||||
// move in each entities local space at once
|
||||
AZ::Quaternion worldOrientation = AZ::Quaternion::CreateIdentity();
|
||||
@@ -876,10 +865,9 @@ namespace AzToolsFramework
|
||||
entityId, entityItLookupIt->second.m_initial.GetTranslation() + localOffset, transformChangedInternally);
|
||||
}
|
||||
break;
|
||||
case ReferenceFrame::Parent:
|
||||
case ReferenceFrame::World:
|
||||
case Influence::Group:
|
||||
{
|
||||
AZ::Quaternion offsetRotation = pivotOrientation.m_worldOrientation *
|
||||
const AZ::Quaternion offsetRotation = pivotOrientation.m_worldOrientation *
|
||||
QuaternionFromTransformNoScaling(entityIdManipulators.m_manipulators->GetLocalTransform().GetInverse());
|
||||
|
||||
const AZ::Vector3 localOffset = offsetRotation.TransformVector(action.LocalPositionOffset());
|
||||
@@ -1062,7 +1050,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
AZStd::chrono::milliseconds timeNow;
|
||||
AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::BroadcastResult(
|
||||
timeNow, &AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Events::EditorViewportInputTimeNow);
|
||||
timeNow,
|
||||
&AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Events::EditorViewportInputTimeNow);
|
||||
return timeNow;
|
||||
});
|
||||
}
|
||||
@@ -1263,7 +1252,7 @@ namespace AzToolsFramework
|
||||
|
||||
AZStd::unique_ptr<TranslationManipulators> translationManipulators = AZStd::make_unique<TranslationManipulators>(
|
||||
TranslationManipulators::Dimensions::Three, AZ::Transform::CreateIdentity(), AZ::Vector3::CreateOne());
|
||||
translationManipulators->SetLineBoundWidth(ManipulatorLineBoundWidth(ViewportUi::DefaultViewportId));
|
||||
translationManipulators->SetLineBoundWidth(ManipulatorLineBoundWidth());
|
||||
|
||||
InitializeManipulators(*translationManipulators);
|
||||
|
||||
@@ -1297,7 +1286,7 @@ namespace AzToolsFramework
|
||||
|
||||
ViewportInteraction::KeyboardModifiers prevModifiers{};
|
||||
translationManipulators->InstallLinearManipulatorMouseMoveCallback(
|
||||
[this, prevModifiers, manipulatorEntityIds](const LinearManipulator::Action& action) mutable -> void
|
||||
[this, prevModifiers, manipulatorEntityIds](const LinearManipulator::Action& action) mutable
|
||||
{
|
||||
UpdateTranslationManipulator(
|
||||
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
|
||||
@@ -1331,7 +1320,7 @@ namespace AzToolsFramework
|
||||
});
|
||||
|
||||
translationManipulators->InstallPlanarManipulatorMouseMoveCallback(
|
||||
[this, prevModifiers, manipulatorEntityIds](const PlanarManipulator::Action& action) mutable -> void
|
||||
[this, prevModifiers, manipulatorEntityIds](const PlanarManipulator::Action& action) mutable
|
||||
{
|
||||
UpdateTranslationManipulator(
|
||||
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
|
||||
@@ -1364,7 +1353,7 @@ namespace AzToolsFramework
|
||||
});
|
||||
|
||||
translationManipulators->InstallSurfaceManipulatorMouseMoveCallback(
|
||||
[this, prevModifiers, manipulatorEntityIds](const SurfaceManipulator::Action& action) mutable -> void
|
||||
[this, prevModifiers, manipulatorEntityIds](const SurfaceManipulator::Action& action) mutable
|
||||
{
|
||||
UpdateTranslationManipulator(
|
||||
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
|
||||
@@ -1391,7 +1380,7 @@ namespace AzToolsFramework
|
||||
|
||||
AZStd::unique_ptr<RotationManipulators> rotationManipulators =
|
||||
AZStd::make_unique<RotationManipulators>(AZ::Transform::CreateIdentity());
|
||||
rotationManipulators->SetCircleBoundWidth(ManipulatorCicleBoundWidth(ViewportUi::DefaultViewportId));
|
||||
rotationManipulators->SetCircleBoundWidth(ManipulatorCicleBoundWidth());
|
||||
|
||||
InitializeManipulators(*rotationManipulators);
|
||||
|
||||
@@ -1415,7 +1404,7 @@ namespace AzToolsFramework
|
||||
AZStd::shared_ptr<SharedRotationState> sharedRotationState = AZStd::make_shared<SharedRotationState>();
|
||||
|
||||
rotationManipulators->InstallLeftMouseDownCallback(
|
||||
[this, sharedRotationState]([[maybe_unused]] const AngularManipulator::Action& action) mutable -> void
|
||||
[this, sharedRotationState]([[maybe_unused]] const AngularManipulator::Action& action) mutable
|
||||
{
|
||||
sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity();
|
||||
sharedRotationState->m_referenceFrameAtMouseDown = m_referenceFrame;
|
||||
@@ -1437,11 +1426,13 @@ namespace AzToolsFramework
|
||||
BeginRecordManipulatorCommand();
|
||||
});
|
||||
|
||||
ViewportInteraction::KeyboardModifiers prevModifiers{};
|
||||
rotationManipulators->InstallMouseMoveCallback(
|
||||
[this, prevModifiers, sharedRotationState](const AngularManipulator::Action& action) mutable -> void
|
||||
[this, prevModifiers = ViewportInteraction::KeyboardModifiers(),
|
||||
sharedRotationState](const AngularManipulator::Action& action) mutable
|
||||
{
|
||||
const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock.value_or(ReferenceFrameFromModifiers(action.m_modifiers));
|
||||
const Influence influence = InfluenceFromModifiers(action.m_modifiers);
|
||||
|
||||
const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta;
|
||||
// store the pivot override frame when positioning the manipulator manually (ctrl)
|
||||
// so we don't lose the orientation when adding/removing entities from the selection
|
||||
@@ -1452,9 +1443,7 @@ namespace AzToolsFramework
|
||||
|
||||
// only update the manipulator orientation if we're rotating in a local reference frame or we're
|
||||
// manually modifying the manipulator orientation independent of the entity by holding ctrl
|
||||
if ((sharedRotationState->m_referenceFrameAtMouseDown == ReferenceFrame::Local &&
|
||||
m_entityIdManipulators.m_lookups.size() == 1) ||
|
||||
action.m_modifiers.Ctrl())
|
||||
if (sharedRotationState->m_referenceFrameAtMouseDown == ReferenceFrame::Local || action.m_modifiers.Ctrl())
|
||||
{
|
||||
m_entityIdManipulators.m_manipulators->SetLocalTransform(AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
manipulatorOrientation, m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation()));
|
||||
@@ -1463,20 +1452,24 @@ namespace AzToolsFramework
|
||||
// save state if we change the type of rotation we're doing to to prevent snapping
|
||||
if (prevModifiers != action.m_modifiers)
|
||||
{
|
||||
UpdateInitialRotation(m_entityIdManipulators);
|
||||
UpdateInitialTransform(m_entityIdManipulators);
|
||||
sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull();
|
||||
}
|
||||
|
||||
// allow the user to modify the orientation without moving the object if ctrl is held
|
||||
if (action.m_modifiers.Ctrl())
|
||||
{
|
||||
UpdateInitialRotation(m_entityIdManipulators);
|
||||
UpdateInitialTransform(m_entityIdManipulators);
|
||||
sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto pivotOrientation = ETCS::CalculateSelectionPivotOrientation(
|
||||
m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, ReferenceFrame::Parent);
|
||||
// only update the pivot override if the orientation is being modified in local space and we have
|
||||
// more than one entity selected (so rotating a single entity does not set the orientation override)
|
||||
if (referenceFrame == ReferenceFrame::Local && sharedRotationState->m_entityIds.size() > 1)
|
||||
{
|
||||
m_pivotOverrideFrame.m_orientationOverride = manipulatorOrientation;
|
||||
}
|
||||
|
||||
// note: must use sorted entityIds based on hierarchy order when updating transforms
|
||||
for (AZ::EntityId entityId : sharedRotationState->m_entityIds)
|
||||
@@ -1492,9 +1485,9 @@ namespace AzToolsFramework
|
||||
const AZ::Transform offsetRotation =
|
||||
AZ::Transform::CreateFromQuaternion(sharedRotationState->m_savedOrientation * action.m_current.m_delta);
|
||||
|
||||
switch (referenceFrame)
|
||||
switch (influence)
|
||||
{
|
||||
case ReferenceFrame::Local:
|
||||
case Influence::Individual:
|
||||
{
|
||||
const AZ::Quaternion rotation = entityIdLookupIt->second.m_initial.GetRotation().GetNormalized();
|
||||
const AZ::Vector3 position = entityIdLookupIt->second.m_initial.GetTranslation();
|
||||
@@ -1510,23 +1503,10 @@ namespace AzToolsFramework
|
||||
AZ::Transform::CreateTranslation(-centerOffset) * AZ::Transform::CreateUniformScale(scale));
|
||||
}
|
||||
break;
|
||||
case ReferenceFrame::Parent:
|
||||
case Influence::Group:
|
||||
{
|
||||
const AZ::Transform pivotTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
pivotOrientation.m_worldOrientation,
|
||||
m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation());
|
||||
|
||||
const AZ::Transform transformInPivotSpace =
|
||||
pivotTransform.GetInverse() * entityIdLookupIt->second.m_initial;
|
||||
|
||||
SetEntityWorldTransform(entityId, pivotTransform * offsetRotation * transformInPivotSpace);
|
||||
}
|
||||
break;
|
||||
case ReferenceFrame::World:
|
||||
{
|
||||
const AZ::Transform pivotTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion::CreateIdentity(),
|
||||
m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation());
|
||||
manipulatorOrientation, m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation());
|
||||
const AZ::Transform transformInPivotSpace =
|
||||
pivotTransform.GetInverse() * entityIdLookupIt->second.m_initial;
|
||||
|
||||
@@ -1561,7 +1541,7 @@ namespace AzToolsFramework
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
AZStd::unique_ptr<ScaleManipulators> scaleManipulators = AZStd::make_unique<ScaleManipulators>(AZ::Transform::CreateIdentity());
|
||||
scaleManipulators->SetLineBoundWidth(ManipulatorLineBoundWidth(ViewportUi::DefaultViewportId));
|
||||
scaleManipulators->SetLineBoundWidth(ManipulatorLineBoundWidth());
|
||||
|
||||
InitializeManipulators(*scaleManipulators);
|
||||
|
||||
@@ -1571,13 +1551,20 @@ namespace AzToolsFramework
|
||||
scaleManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
|
||||
scaleManipulators->ConfigureView(2.0f, AZ::Color::CreateOne(), AZ::Color::CreateOne(), AZ::Color::CreateOne());
|
||||
|
||||
// lambdas capture shared_ptr by value to increment ref count
|
||||
auto manipulatorEntityIds = AZStd::make_shared<ManipulatorEntityIds>();
|
||||
|
||||
auto uniformLeftMouseDownCallback = [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action)
|
||||
struct SharedScaleState
|
||||
{
|
||||
AZ::Vector3 m_savedScaleOffset = AZ::Vector3::CreateZero();
|
||||
EntityIdList m_entityIds;
|
||||
};
|
||||
|
||||
// lambdas capture shared_ptr by value to increment ref count
|
||||
auto sharedScaleState = AZStd::make_shared<SharedScaleState>();
|
||||
|
||||
auto uniformLeftMouseDownCallback = [this, sharedScaleState]([[maybe_unused]] const LinearManipulator::Action& action)
|
||||
{
|
||||
sharedScaleState->m_savedScaleOffset = AZ::Vector3::CreateZero();
|
||||
// important to sort entityIds based on hierarchy order when updating transforms
|
||||
BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds);
|
||||
BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, sharedScaleState->m_entityIds);
|
||||
|
||||
for (auto& entityIdLookup : m_entityIdManipulators.m_lookups)
|
||||
{
|
||||
@@ -1591,20 +1578,32 @@ namespace AzToolsFramework
|
||||
m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform());
|
||||
};
|
||||
|
||||
auto uniformLeftMouseUpCallback = [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action)
|
||||
auto uniformLeftMouseUpCallback = [this, sharedScaleState]([[maybe_unused]] const LinearManipulator::Action& action)
|
||||
{
|
||||
AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast(
|
||||
&AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged,
|
||||
manipulatorEntityIds->m_entityIds);
|
||||
&AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged, sharedScaleState->m_entityIds);
|
||||
|
||||
m_entityIdManipulators.m_manipulators->SetLocalTransform(RecalculateAverageManipulatorTransform(
|
||||
m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame));
|
||||
};
|
||||
|
||||
auto uniformLeftMouseMoveCallback = [this, manipulatorEntityIds](const LinearManipulator::Action& action)
|
||||
auto uniformLeftMouseMoveCallback = [this, sharedScaleState, prevModifiers = ViewportInteraction::KeyboardModifiers()](
|
||||
const LinearManipulator::Action& action) mutable
|
||||
{
|
||||
// do nothing to modify the manipulator
|
||||
if (action.m_modifiers.Ctrl())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (prevModifiers != action.m_modifiers)
|
||||
{
|
||||
UpdateInitialTransform(m_entityIdManipulators);
|
||||
sharedScaleState->m_savedScaleOffset = action.LocalScaleOffset();
|
||||
}
|
||||
|
||||
// note: must use sorted entityIds based on hierarchy order when updating transforms
|
||||
for (AZ::EntityId entityId : manipulatorEntityIds->m_entityIds)
|
||||
for (AZ::EntityId entityId : sharedScaleState->m_entityIds)
|
||||
{
|
||||
auto entityIdLookupIt = m_entityIdManipulators.m_lookups.find(entityId);
|
||||
if (entityIdLookupIt == m_entityIdManipulators.m_lookups.end())
|
||||
@@ -1620,26 +1619,33 @@ namespace AzToolsFramework
|
||||
return vec.GetX() + vec.GetY() + vec.GetZ();
|
||||
};
|
||||
|
||||
const float uniformScale = action.m_start.m_sign * sumVectorElements(action.LocalScaleOffset());
|
||||
const float uniformScale =
|
||||
action.m_start.m_sign * sumVectorElements(action.LocalScaleOffset() - sharedScaleState->m_savedScaleOffset);
|
||||
const float scale = AZ::GetClamp(1.0f + uniformScale / initialScale, AZ::MinTransformScale, AZ::MaxTransformScale);
|
||||
const AZ::Transform scaleTransform = AZ::Transform::CreateUniformScale(scale);
|
||||
|
||||
if (action.m_modifiers.Alt())
|
||||
switch (InfluenceFromModifiers(action.m_modifiers))
|
||||
{
|
||||
const AZ::Transform pivotTransform = TransformNormalizedScale(entityIdLookupIt->second.m_initial);
|
||||
const AZ::Transform transformInPivotSpace = pivotTransform.GetInverse() * initial;
|
||||
case Influence::Individual:
|
||||
{
|
||||
const AZ::Transform pivotTransform = TransformNormalizedScale(entityIdLookupIt->second.m_initial);
|
||||
const AZ::Transform transformInPivotSpace = pivotTransform.GetInverse() * initial;
|
||||
|
||||
SetEntityWorldTransform(entityId, pivotTransform * scaleTransform * transformInPivotSpace);
|
||||
}
|
||||
else
|
||||
{
|
||||
const AZ::Transform pivotTransform =
|
||||
TransformNormalizedScale(m_entityIdManipulators.m_manipulators->GetLocalTransform());
|
||||
const AZ::Transform transformInPivotSpace = pivotTransform.GetInverse() * initial;
|
||||
SetEntityWorldTransform(entityId, pivotTransform * scaleTransform * transformInPivotSpace);
|
||||
}
|
||||
break;
|
||||
case Influence::Group:
|
||||
{
|
||||
const AZ::Transform pivotTransform =
|
||||
TransformNormalizedScale(m_entityIdManipulators.m_manipulators->GetLocalTransform());
|
||||
const AZ::Transform transformInPivotSpace = pivotTransform.GetInverse() * initial;
|
||||
|
||||
SetEntityWorldTransform(entityId, pivotTransform * scaleTransform * transformInPivotSpace);
|
||||
SetEntityWorldTransform(entityId, pivotTransform * scaleTransform * transformInPivotSpace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prevModifiers = action.m_modifiers;
|
||||
};
|
||||
|
||||
scaleManipulators->InstallAxisLeftMouseDownCallback(uniformLeftMouseDownCallback);
|
||||
@@ -2729,8 +2735,7 @@ namespace AzToolsFramework
|
||||
|
||||
if (m_pivotOverrideFrame.m_orientationOverride && m_entityIdManipulators.m_manipulators)
|
||||
{
|
||||
m_pivotOverrideFrame.m_orientationOverride =
|
||||
QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform());
|
||||
m_pivotOverrideFrame.m_orientationOverride = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetRotation();
|
||||
}
|
||||
|
||||
if (m_pivotOverrideFrame.m_translationOverride && m_entityIdManipulators.m_manipulators)
|
||||
@@ -3337,7 +3342,7 @@ namespace AzToolsFramework
|
||||
|
||||
display.SetLineWidth(4.0f);
|
||||
|
||||
const auto axisFlip = [&transform, &cameraState](const AZ::Vector3& axis) -> float
|
||||
const auto axisFlip = [&transform, &cameraState](const AZ::Vector3& axis)
|
||||
{
|
||||
return ShouldFlipCameraAxis(
|
||||
AZ::Transform::CreateIdentity(), transform.GetTranslation(), TransformDirectionNoScaling(transform, axis),
|
||||
@@ -3554,7 +3559,7 @@ namespace AzToolsFramework
|
||||
// screen space
|
||||
const auto calculateGizmoAxis = [&cameraView, &cameraProjection, &screenOffset](const AZ::Vector3& axis)
|
||||
{
|
||||
auto result = AZ::Vector2(AzFramework::WorldToScreenNDC(axis, cameraView, cameraProjection));
|
||||
auto result = AZ::Vector2(AzFramework::WorldToScreenNdc(axis, cameraView, cameraProjection));
|
||||
result.SetY(1.0f - result.GetY());
|
||||
return result + screenOffset;
|
||||
};
|
||||
|
||||
+10
-1
@@ -96,6 +96,14 @@ namespace AzToolsFramework
|
||||
AZ::u8 m_pickTypes = PickType::None; //!< What mode(s) were we in when picking an EntityId override.
|
||||
};
|
||||
|
||||
//! How a manipulator should treat an adjustment.
|
||||
//! @note Determines if a transform is applied to an individual entity or the whole group.
|
||||
enum class Influence
|
||||
{
|
||||
Group,
|
||||
Individual
|
||||
};
|
||||
|
||||
//! What frame/space is the manipulator currently operating in.
|
||||
enum class ReferenceFrame
|
||||
{
|
||||
@@ -328,7 +336,8 @@ namespace AzToolsFramework
|
||||
OptionalFrame m_pivotOverrideFrame; //!< Has a pivot override been set.
|
||||
Mode m_mode = Mode::Translation; //!< Manipulator mode - default to translation.
|
||||
Pivot m_pivotMode = Pivot::Object; //!< Entity pivot mode - default to object (authored root).
|
||||
ReferenceFrame m_referenceFrame = ReferenceFrame::Parent; //!< What reference frame is the Manipulator currently operating in.
|
||||
ReferenceFrame m_referenceFrame = ReferenceFrame::Local; //!< What reference frame is the Manipulator currently operating in.
|
||||
Influence m_influence = Influence::Group; //!< What sphere of influence does the Manipulator have.
|
||||
Frame m_axisPreview; //!< Axes of entity at the time of mouse down to indicate delta of translation.
|
||||
bool m_triedToRefresh = false; //!< Did a refresh event occur to recalculate the current Manipulator transform.
|
||||
//! Was EditorTransformComponentSelection responsible for the most recent entity selection change.
|
||||
|
||||
@@ -242,11 +242,11 @@ namespace UnitTest
|
||||
{
|
||||
// the initial starting position of the entities
|
||||
AZ::TransformBus::Event(
|
||||
m_entityId1, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(m_entity1WorldTranslation));
|
||||
m_entityId1, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(Entity1WorldTranslation));
|
||||
AZ::TransformBus::Event(
|
||||
m_entityId2, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(m_entity2WorldTranslation));
|
||||
m_entityId2, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(Entity2WorldTranslation));
|
||||
AZ::TransformBus::Event(
|
||||
m_entityId3, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(m_entity3WorldTranslation));
|
||||
m_entityId3, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(Entity3WorldTranslation));
|
||||
}
|
||||
|
||||
static void PositionCamera(AzFramework::CameraState& cameraState)
|
||||
@@ -261,9 +261,10 @@ namespace UnitTest
|
||||
AZ::EntityId m_entityId1;
|
||||
AZ::EntityId m_entityId2;
|
||||
AZ::EntityId m_entityId3;
|
||||
AZ::Vector3 m_entity1WorldTranslation = AZ::Vector3(5.0f, 15.0f, 10.0f);
|
||||
AZ::Vector3 m_entity2WorldTranslation = AZ::Vector3(5.0f, 14.0f, 10.0f);
|
||||
AZ::Vector3 m_entity3WorldTranslation = AZ::Vector3(5.0f, 16.0f, 10.0f);
|
||||
|
||||
static inline const AZ::Vector3 Entity1WorldTranslation = AZ::Vector3(5.0f, 15.0f, 10.0f);
|
||||
static inline const AZ::Vector3 Entity2WorldTranslation = AZ::Vector3(5.0f, 14.0f, 10.0f);
|
||||
static inline const AZ::Vector3 Entity3WorldTranslation = AZ::Vector3(5.0f, 16.0f, 10.0f);
|
||||
};
|
||||
|
||||
void ArrangeIndividualRotatedEntitySelection(const AzToolsFramework::EntityIdList& entityIds, const AZ::Quaternion& orientation)
|
||||
@@ -371,16 +372,16 @@ namespace UnitTest
|
||||
// Given
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
ArrangeIndividualRotatedEntitySelection(m_entityIds, AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)));
|
||||
const auto entityTransform = AZ::Transform::CreateFromQuaternion(AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)));
|
||||
ArrangeIndividualRotatedEntitySelection(m_entityIds, entityTransform.GetRotation());
|
||||
RefreshManipulators(EditorTransformComponentSelectionRequestBus::Events::RefreshType::All);
|
||||
|
||||
SetTransformMode(EditorTransformComponentSelectionRequestBus::Events::Mode::Rotation);
|
||||
|
||||
const AZ::Transform manipulatorTransformBefore = GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity());
|
||||
|
||||
// check preconditions - manipulator transform matches parent/world transform (identity)
|
||||
EXPECT_THAT(manipulatorTransformBefore.GetBasisY(), IsClose(AZ::Vector3::CreateAxisY()));
|
||||
EXPECT_THAT(manipulatorTransformBefore.GetBasisZ(), IsClose(AZ::Vector3::CreateAxisZ()));
|
||||
// check preconditions - manipulator transform matches the entity transform
|
||||
EXPECT_THAT(manipulatorTransformBefore, IsClose(entityTransform));
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -624,7 +625,7 @@ namespace UnitTest
|
||||
EXPECT_TRUE(selectedEntitiesBefore.empty());
|
||||
|
||||
// calculate the position in screen space of the initial entity position
|
||||
const auto entity1ScreenPosition = AzFramework::WorldToScreen(m_entity1WorldTranslation, m_cameraState);
|
||||
const auto entity1ScreenPosition = AzFramework::WorldToScreen(Entity1WorldTranslation, m_cameraState);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(true)
|
||||
@@ -649,7 +650,7 @@ namespace UnitTest
|
||||
EXPECT_TRUE(selectedEntitiesBefore.empty());
|
||||
|
||||
// calculate the position in screen space of the initial entity position
|
||||
const auto entity1ScreenPosition = AzFramework::WorldToScreen(m_entity1WorldTranslation, m_cameraState);
|
||||
const auto entity1ScreenPosition = AzFramework::WorldToScreen(Entity1WorldTranslation, m_cameraState);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(false)
|
||||
@@ -728,7 +729,7 @@ namespace UnitTest
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(Entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(true)
|
||||
@@ -754,7 +755,7 @@ namespace UnitTest
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(Entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(false)
|
||||
@@ -780,7 +781,7 @@ namespace UnitTest
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(Entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(true)
|
||||
@@ -806,7 +807,7 @@ namespace UnitTest
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(Entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(false)
|
||||
@@ -832,7 +833,7 @@ namespace UnitTest
|
||||
AzToolsFramework::SelectEntities({ m_entityId1, m_entityId2 });
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(Entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(true)
|
||||
@@ -858,7 +859,7 @@ namespace UnitTest
|
||||
AzToolsFramework::SelectEntities({ m_entityId1, m_entityId2 });
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(Entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(false)
|
||||
@@ -1001,7 +1002,7 @@ namespace UnitTest
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(Entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// single click select entity2
|
||||
m_actionDispatcher->SetStickySelect(false)
|
||||
@@ -1035,7 +1036,7 @@ namespace UnitTest
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(Entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// single click select entity2
|
||||
m_actionDispatcher->SetStickySelect(GetParam())
|
||||
@@ -1056,7 +1057,7 @@ namespace UnitTest
|
||||
manipulatorTransform, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
|
||||
|
||||
EXPECT_THAT(manipulatorTransform->GetTranslation(), IsClose(m_entity2WorldTranslation));
|
||||
EXPECT_THAT(manipulatorTransform->GetTranslation(), IsClose(Entity2WorldTranslation));
|
||||
}
|
||||
|
||||
TEST_P(
|
||||
@@ -1069,7 +1070,7 @@ namespace UnitTest
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(Entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// position in space above the entities
|
||||
const auto clickOffPositionWorld = AZ::Vector3(5.0f, 15.0f, 12.0f);
|
||||
@@ -1096,7 +1097,7 @@ namespace UnitTest
|
||||
manipulatorTransform, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
|
||||
|
||||
EXPECT_THAT(manipulatorTransform->GetTranslation(), IsClose(m_entity2WorldTranslation));
|
||||
EXPECT_THAT(manipulatorTransform->GetTranslation(), IsClose(Entity2WorldTranslation));
|
||||
})
|
||||
->MousePosition(clickOffPositionScreen)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
|
||||
@@ -1113,11 +1114,560 @@ namespace UnitTest
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
|
||||
|
||||
// manipulator transform is reset
|
||||
EXPECT_THAT(manipulatorTransform->GetTranslation(), IsClose(m_entity1WorldTranslation));
|
||||
EXPECT_THAT(manipulatorTransform->GetTranslation(), IsClose(Entity1WorldTranslation));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(All, EditorTransformComponentSelectionViewportPickingManipulatorTestFixtureParam, testing::Values(true, false));
|
||||
|
||||
// create alias for EditorTransformComponentSelectionViewportPickingManipulatorTestFixture to help group tests
|
||||
using EditorTransformComponentSelectionManipulatorInteractionTestFixture =
|
||||
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture;
|
||||
|
||||
// type to group related inputs and outcomes for parameterized tests (single entity)
|
||||
struct ManipulatorOptionsSingle
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier m_keyboardModifier;
|
||||
AZ::Transform m_expectedManipulatorTransformAfter;
|
||||
AZ::Transform m_expectedEntityTransformAfter;
|
||||
};
|
||||
|
||||
class EditorTransformComponentSelectionRotationManipulatorSingleEntityTestFixtureParam
|
||||
: public EditorTransformComponentSelectionManipulatorInteractionTestFixture
|
||||
, public ::testing::WithParamInterface<ManipulatorOptionsSingle>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(
|
||||
EditorTransformComponentSelectionRotationManipulatorSingleEntityTestFixtureParam,
|
||||
RotatingASingleEntityWithDifferentModifierCombinations)
|
||||
{
|
||||
using AzToolsFramework::EditorTransformComponentSelectionRequestBus;
|
||||
|
||||
PositionEntities();
|
||||
PositionCamera(m_cameraState);
|
||||
|
||||
SetTransformMode(EditorTransformComponentSelectionRequestBus::Events::Mode::Rotation);
|
||||
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
const float screenToWorldMultiplier = AzToolsFramework::CalculateScreenToWorldMultiplier(Entity1WorldTranslation, m_cameraState);
|
||||
const float manipulatorRadius = 2.0f * screenToWorldMultiplier;
|
||||
|
||||
const auto rotationManipulatorStartHoldWorldPosition = Entity1WorldTranslation +
|
||||
AZ::Quaternion::CreateRotationX(AZ::DegToRad(-45.0f)).TransformVector(AZ::Vector3::CreateAxisY(-manipulatorRadius));
|
||||
const auto rotationManipulatorEndHoldWorldPosition = Entity1WorldTranslation +
|
||||
AZ::Quaternion::CreateRotationX(AZ::DegToRad(-135.0f)).TransformVector(AZ::Vector3::CreateAxisY(-manipulatorRadius));
|
||||
|
||||
// calculate screen space positions
|
||||
const auto rotationManipulatorHoldScreenPosition =
|
||||
AzFramework::WorldToScreen(rotationManipulatorStartHoldWorldPosition, m_cameraState);
|
||||
const auto rotationManipulatorEndHoldScreenPosition =
|
||||
AzFramework::WorldToScreen(rotationManipulatorEndHoldWorldPosition, m_cameraState);
|
||||
|
||||
m_actionDispatcher->CameraState(m_cameraState)
|
||||
->MousePosition(rotationManipulatorHoldScreenPosition)
|
||||
->KeyboardModifierDown(GetParam().m_keyboardModifier)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(rotationManipulatorEndHoldScreenPosition)
|
||||
->MouseLButtonUp();
|
||||
|
||||
const auto expectedEntityTransform = GetParam().m_expectedEntityTransformAfter;
|
||||
const auto expectedManipulatorTransform = GetParam().m_expectedManipulatorTransformAfter;
|
||||
|
||||
const auto manipulatorTransform = GetManipulatorTransform();
|
||||
const auto entityTransform = AzToolsFramework::GetWorldTransform(m_entityId1);
|
||||
|
||||
EXPECT_THAT(*manipulatorTransform, IsClose(expectedManipulatorTransform));
|
||||
EXPECT_THAT(entityTransform, IsClose(expectedEntityTransform));
|
||||
}
|
||||
|
||||
static const AZ::Transform ExpectedTransformAfterLocalRotationManipulatorMotion = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion::CreateRotationX(AZ::DegToRad(-90.0f)),
|
||||
EditorTransformComponentSelectionViewportPickingFixture::Entity1WorldTranslation);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
All,
|
||||
EditorTransformComponentSelectionRotationManipulatorSingleEntityTestFixtureParam,
|
||||
testing::Values(
|
||||
// this replicates rotating an entity in local space with no modifiers held
|
||||
// manipulator and entity rotate
|
||||
ManipulatorOptionsSingle{ AzToolsFramework::ViewportInteraction::KeyboardModifier::None,
|
||||
ExpectedTransformAfterLocalRotationManipulatorMotion,
|
||||
ExpectedTransformAfterLocalRotationManipulatorMotion },
|
||||
// this replicates rotating an entity in local space with the alt modifier held
|
||||
// manipulator and entity rotate
|
||||
ManipulatorOptionsSingle{ AzToolsFramework::ViewportInteraction::KeyboardModifier::Alt,
|
||||
ExpectedTransformAfterLocalRotationManipulatorMotion,
|
||||
ExpectedTransformAfterLocalRotationManipulatorMotion },
|
||||
// this replicates rotating an entity in world space with the shift modifier held
|
||||
// entity rotates, manipulator remains aligned to world
|
||||
ManipulatorOptionsSingle{
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier::Shift,
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity1WorldTranslation),
|
||||
ExpectedTransformAfterLocalRotationManipulatorMotion },
|
||||
// this replicates rotating the manipulator in local space with the ctrl modifier held (entity is unchanged)
|
||||
ManipulatorOptionsSingle{
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier::Ctrl, ExpectedTransformAfterLocalRotationManipulatorMotion,
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity1WorldTranslation) }));
|
||||
|
||||
// type to group related inputs and outcomes for parameterized tests (two entities)
|
||||
struct ManipulatorOptionsMultiple
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier m_keyboardModifier;
|
||||
AZ::Transform m_expectedManipulatorTransformAfter;
|
||||
AZ::Transform m_firstExpectedEntityTransformAfter;
|
||||
AZ::Transform m_secondExpectedEntityTransformAfter;
|
||||
};
|
||||
|
||||
class EditorTransformComponentSelectionRotationManipulatorMultipleEntityTestFixtureParam
|
||||
: public EditorTransformComponentSelectionManipulatorInteractionTestFixture
|
||||
, public ::testing::WithParamInterface<ManipulatorOptionsMultiple>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(
|
||||
EditorTransformComponentSelectionRotationManipulatorMultipleEntityTestFixtureParam,
|
||||
RotatingMultipleEntitiesWithDifferentModifierCombinations)
|
||||
{
|
||||
using AzToolsFramework::EditorTransformComponentSelectionRequestBus;
|
||||
|
||||
PositionEntities();
|
||||
PositionCamera(m_cameraState);
|
||||
|
||||
SetTransformMode(EditorTransformComponentSelectionRequestBus::Events::Mode::Rotation);
|
||||
|
||||
AzToolsFramework::SelectEntities({ m_entityId2, m_entityId3 });
|
||||
|
||||
// manipulator should be centered between the two entities
|
||||
const auto initialManipulatorTransform = GetManipulatorTransform();
|
||||
|
||||
const float screenToWorldMultiplier =
|
||||
AzToolsFramework::CalculateScreenToWorldMultiplier(initialManipulatorTransform->GetTranslation(), m_cameraState);
|
||||
const float manipulatorRadius = 2.0f * screenToWorldMultiplier;
|
||||
|
||||
const auto rotationManipulatorStartHoldWorldPosition = initialManipulatorTransform->GetTranslation() +
|
||||
AZ::Quaternion::CreateRotationX(AZ::DegToRad(-45.0f)).TransformVector(AZ::Vector3::CreateAxisY(-manipulatorRadius));
|
||||
const auto rotationManipulatorEndHoldWorldPosition = initialManipulatorTransform->GetTranslation() +
|
||||
AZ::Quaternion::CreateRotationX(AZ::DegToRad(-135.0f)).TransformVector(AZ::Vector3::CreateAxisY(-manipulatorRadius));
|
||||
|
||||
// calculate screen space positions
|
||||
const auto rotationManipulatorHoldScreenPosition =
|
||||
AzFramework::WorldToScreen(rotationManipulatorStartHoldWorldPosition, m_cameraState);
|
||||
const auto rotationManipulatorEndHoldScreenPosition =
|
||||
AzFramework::WorldToScreen(rotationManipulatorEndHoldWorldPosition, m_cameraState);
|
||||
|
||||
m_actionDispatcher->CameraState(m_cameraState)
|
||||
->MousePosition(rotationManipulatorHoldScreenPosition)
|
||||
->KeyboardModifierDown(GetParam().m_keyboardModifier)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(rotationManipulatorEndHoldScreenPosition)
|
||||
->MouseLButtonUp();
|
||||
|
||||
const auto expectedEntity2Transform = GetParam().m_firstExpectedEntityTransformAfter;
|
||||
const auto expectedEntity3Transform = GetParam().m_secondExpectedEntityTransformAfter;
|
||||
const auto expectedManipulatorTransform = GetParam().m_expectedManipulatorTransformAfter;
|
||||
|
||||
const auto manipulatorTransformAfter = GetManipulatorTransform();
|
||||
const auto entity2Transform = AzToolsFramework::GetWorldTransform(m_entityId2);
|
||||
const auto entity3Transform = AzToolsFramework::GetWorldTransform(m_entityId3);
|
||||
|
||||
EXPECT_THAT(*manipulatorTransformAfter, IsClose(expectedManipulatorTransform));
|
||||
EXPECT_THAT(entity2Transform, IsClose(expectedEntity2Transform));
|
||||
EXPECT_THAT(entity3Transform, IsClose(expectedEntity3Transform));
|
||||
}
|
||||
|
||||
// note: The aggregate manipulator position will be the average of entity 2 and 3 combined which
|
||||
// winds up being the same as entity 1
|
||||
static const AZ::Vector3 AggregateManipulatorPositionWithEntity2and3Selected =
|
||||
EditorTransformComponentSelectionViewportPickingFixture::Entity1WorldTranslation;
|
||||
|
||||
static const AZ::Transform ExpectedEntity2TransformAfterLocalGroupRotationManipulatorMotion =
|
||||
AZ::Transform::CreateTranslation(AggregateManipulatorPositionWithEntity2and3Selected) *
|
||||
AZ::Transform::CreateFromQuaternion(AZ::Quaternion::CreateRotationX(AZ::DegToRad(-90.0f))) *
|
||||
AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(-1.0f));
|
||||
static const AZ::Transform ExpectedEntity3TransformAfterLocalGroupRotationManipulatorMotion =
|
||||
AZ::Transform::CreateTranslation(AggregateManipulatorPositionWithEntity2and3Selected) *
|
||||
AZ::Transform::CreateFromQuaternion(AZ::Quaternion::CreateRotationX(AZ::DegToRad(-90.0f))) *
|
||||
AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(1.0f));
|
||||
static const AZ::Transform ExpectedEntity2TransformAfterLocalIndividualRotationManipulatorMotion =
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity2WorldTranslation) *
|
||||
AZ::Transform::CreateFromQuaternion(AZ::Quaternion::CreateRotationX(AZ::DegToRad(-90.0f)));
|
||||
static const AZ::Transform ExpectedEntity3TransformAfterLocalIndividualRotationManipulatorMotion =
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity3WorldTranslation) *
|
||||
AZ::Transform::CreateFromQuaternion(AZ::Quaternion::CreateRotationX(AZ::DegToRad(-90.0f)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
All,
|
||||
EditorTransformComponentSelectionRotationManipulatorMultipleEntityTestFixtureParam,
|
||||
testing::Values(
|
||||
// this replicates rotating a group of entities in local space with no modifiers held
|
||||
// manipulator and entity rotate
|
||||
ManipulatorOptionsMultiple{ AzToolsFramework::ViewportInteraction::KeyboardModifier::None,
|
||||
ExpectedTransformAfterLocalRotationManipulatorMotion,
|
||||
ExpectedEntity2TransformAfterLocalGroupRotationManipulatorMotion,
|
||||
ExpectedEntity3TransformAfterLocalGroupRotationManipulatorMotion },
|
||||
// this replicates rotating a group of entities in local space with the alt modifier held
|
||||
// manipulator and entity rotate
|
||||
ManipulatorOptionsMultiple{ AzToolsFramework::ViewportInteraction::KeyboardModifier::Alt,
|
||||
ExpectedTransformAfterLocalRotationManipulatorMotion,
|
||||
ExpectedEntity2TransformAfterLocalIndividualRotationManipulatorMotion,
|
||||
ExpectedEntity3TransformAfterLocalIndividualRotationManipulatorMotion },
|
||||
// this replicates rotating a group of entities in world space with the shift modifier held
|
||||
// entity rotates, manipulator remains aligned to world
|
||||
ManipulatorOptionsMultiple{
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier::Shift,
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity1WorldTranslation),
|
||||
ExpectedEntity2TransformAfterLocalGroupRotationManipulatorMotion,
|
||||
ExpectedEntity3TransformAfterLocalGroupRotationManipulatorMotion },
|
||||
// this replicates rotating the manipulator in local space with the ctrl modifier held (entity is unchanged)
|
||||
ManipulatorOptionsMultiple{
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier::Ctrl, ExpectedTransformAfterLocalRotationManipulatorMotion,
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity2WorldTranslation),
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity3WorldTranslation) }));
|
||||
|
||||
class EditorTransformComponentSelectionTranslationManipulatorSingleEntityTestFixtureParam
|
||||
: public EditorTransformComponentSelectionManipulatorInteractionTestFixture
|
||||
, public ::testing::WithParamInterface<ManipulatorOptionsSingle>
|
||||
{
|
||||
};
|
||||
|
||||
static const float LinearManipulatorYAxisMovement = -3.0f;
|
||||
static const float LinearManipulatorZAxisMovement = 2.0f;
|
||||
|
||||
TEST_P(
|
||||
EditorTransformComponentSelectionTranslationManipulatorSingleEntityTestFixtureParam,
|
||||
TranslatingASingleEntityWithDifferentModifierCombinations)
|
||||
{
|
||||
using AzToolsFramework::EditorTransformComponentSelectionRequestBus;
|
||||
|
||||
PositionEntities();
|
||||
|
||||
// move camera up and to the left so it's just above the normal row of entities
|
||||
AzFramework::SetCameraTransform(
|
||||
m_cameraState,
|
||||
AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 14.5, 11.0f)));
|
||||
|
||||
SetTransformMode(EditorTransformComponentSelectionRequestBus::Events::Mode::Translation);
|
||||
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
const auto entity1Transform = AzToolsFramework::GetWorldTransform(m_entityId1);
|
||||
|
||||
const float screenToWorldMultiplier = AzToolsFramework::CalculateScreenToWorldMultiplier(
|
||||
AzToolsFramework::GetWorldTransform(m_entityId1).GetTranslation(), m_cameraState);
|
||||
|
||||
// calculate positions for two click and drag motions (moving a linear manipulator)
|
||||
// begin each click in the center of the line of the linear manipulators
|
||||
const auto translationManipulatorStartHoldWorldPosition1 =
|
||||
AzToolsFramework::GetWorldTransform(m_entityId1).GetTranslation() + entity1Transform.GetBasisZ() * screenToWorldMultiplier;
|
||||
const auto translationManipulatorEndHoldWorldPosition1 =
|
||||
translationManipulatorStartHoldWorldPosition1 + AZ::Vector3::CreateAxisZ(LinearManipulatorZAxisMovement);
|
||||
const auto translationManipulatorStartHoldWorldPosition2 = AzToolsFramework::GetWorldTransform(m_entityId1).GetTranslation() +
|
||||
AZ::Vector3::CreateAxisZ(LinearManipulatorZAxisMovement) - entity1Transform.GetBasisY() * screenToWorldMultiplier;
|
||||
const auto translationManipulatorEndHoldWorldPosition2 =
|
||||
translationManipulatorStartHoldWorldPosition2 + AZ::Vector3::CreateAxisY(LinearManipulatorYAxisMovement);
|
||||
|
||||
// transform to screen space
|
||||
const auto translationManipulatorStartHoldScreenPosition1 =
|
||||
AzFramework::WorldToScreen(translationManipulatorStartHoldWorldPosition1, m_cameraState);
|
||||
const auto translationManipulatorEndHoldScreenPosition1 =
|
||||
AzFramework::WorldToScreen(translationManipulatorEndHoldWorldPosition1, m_cameraState);
|
||||
const auto translationManipulatorStartHoldScreenPosition2 =
|
||||
AzFramework::WorldToScreen(translationManipulatorStartHoldWorldPosition2, m_cameraState);
|
||||
const auto translationManipulatorEndHoldScreenPosition2 =
|
||||
AzFramework::WorldToScreen(translationManipulatorEndHoldWorldPosition2, m_cameraState);
|
||||
|
||||
m_actionDispatcher->CameraState(m_cameraState)
|
||||
->MousePosition(translationManipulatorStartHoldScreenPosition1)
|
||||
->KeyboardModifierDown(GetParam().m_keyboardModifier)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(translationManipulatorEndHoldScreenPosition1)
|
||||
->MouseLButtonUp()
|
||||
->MousePosition(translationManipulatorStartHoldScreenPosition2)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(translationManipulatorEndHoldScreenPosition2)
|
||||
->MouseLButtonUp();
|
||||
|
||||
const auto expectedEntityTransform = GetParam().m_expectedEntityTransformAfter;
|
||||
const auto expectedManipulatorTransform = GetParam().m_expectedManipulatorTransformAfter;
|
||||
|
||||
const auto manipulatorTransform = GetManipulatorTransform();
|
||||
const auto entityTransform = AzToolsFramework::GetWorldTransform(m_entityId1);
|
||||
|
||||
EXPECT_THAT(*manipulatorTransform, IsCloseTolerance(expectedManipulatorTransform, 0.01f));
|
||||
EXPECT_THAT(entityTransform, IsCloseTolerance(expectedEntityTransform, 0.01f));
|
||||
}
|
||||
|
||||
static const AZ::Transform ExpectedTransformAfterLocalTranslationManipulatorMotion = AZ::Transform::CreateTranslation(
|
||||
EditorTransformComponentSelectionViewportPickingFixture::Entity1WorldTranslation +
|
||||
AZ::Vector3(0.0f, LinearManipulatorYAxisMovement, LinearManipulatorZAxisMovement));
|
||||
|
||||
// where the manipulator should end up after the input from TranslatingMultipleEntitiesWithDifferentModifierCombinations
|
||||
static const AZ::Transform ExpectedManipulatorTransformAfterGroupTranslationManipulatorMotion = AZ::Transform::CreateTranslation(
|
||||
AggregateManipulatorPositionWithEntity2and3Selected +
|
||||
AZ::Vector3(0.0f, LinearManipulatorYAxisMovement, LinearManipulatorZAxisMovement));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
All,
|
||||
EditorTransformComponentSelectionTranslationManipulatorSingleEntityTestFixtureParam,
|
||||
testing::Values(
|
||||
// this replicates translating an entity in local space with no modifiers held
|
||||
// manipulator and entity translate
|
||||
ManipulatorOptionsSingle{ AzToolsFramework::ViewportInteraction::KeyboardModifier::None,
|
||||
ExpectedTransformAfterLocalTranslationManipulatorMotion,
|
||||
ExpectedTransformAfterLocalTranslationManipulatorMotion },
|
||||
// this replicates translating an entity in local space with the alt modifier held
|
||||
// manipulator and entity translate (to the user, equivalent to no modifiers with one entity selected)
|
||||
ManipulatorOptionsSingle{ AzToolsFramework::ViewportInteraction::KeyboardModifier::Alt,
|
||||
ExpectedTransformAfterLocalTranslationManipulatorMotion,
|
||||
ExpectedTransformAfterLocalTranslationManipulatorMotion },
|
||||
// this replicates translating an entity in world space with the shift modifier held
|
||||
// manipulator and entity translate
|
||||
ManipulatorOptionsSingle{ AzToolsFramework::ViewportInteraction::KeyboardModifier::Shift,
|
||||
ExpectedTransformAfterLocalTranslationManipulatorMotion,
|
||||
ExpectedTransformAfterLocalTranslationManipulatorMotion },
|
||||
// this replicates translating the manipulator in local space with the ctrl modifier held
|
||||
// entity is unchanged, manipulator moves
|
||||
ManipulatorOptionsSingle{
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier::Ctrl, ExpectedTransformAfterLocalTranslationManipulatorMotion,
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity1WorldTranslation) }));
|
||||
|
||||
class EditorTransformComponentSelectionTranslationManipulatorMultipleEntityTestFixtureParam
|
||||
: public EditorTransformComponentSelectionManipulatorInteractionTestFixture
|
||||
, public ::testing::WithParamInterface<ManipulatorOptionsMultiple>
|
||||
{
|
||||
};
|
||||
|
||||
static const AZ::Transform Entity2RotationForLocalTranslation =
|
||||
AZ::Transform::CreateFromQuaternion(AZ::Quaternion::CreateRotationZ(AZ::DegToRad(90.0f)));
|
||||
|
||||
TEST_P(
|
||||
EditorTransformComponentSelectionTranslationManipulatorMultipleEntityTestFixtureParam,
|
||||
TranslatingMultipleEntitiesWithDifferentModifierCombinations)
|
||||
{
|
||||
using AzToolsFramework::EditorTransformComponentSelectionRequestBus;
|
||||
|
||||
PositionEntities();
|
||||
|
||||
// move camera up and to the left so it's just above the normal row of entities
|
||||
AzFramework::SetCameraTransform(
|
||||
m_cameraState,
|
||||
AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 14.5, 11.0f)));
|
||||
|
||||
SetTransformMode(EditorTransformComponentSelectionRequestBus::Events::Mode::Translation);
|
||||
|
||||
// give entity 2 a different orientation to entity 3 so when moving in local space their translation vectors will be different
|
||||
AZ::TransformBus::Event(
|
||||
m_entityId2, &AZ::TransformBus::Events::SetWorldRotationQuaternion, Entity2RotationForLocalTranslation.GetRotation());
|
||||
|
||||
AzToolsFramework::SelectEntities({ m_entityId2, m_entityId3 });
|
||||
|
||||
const auto initialManipulatorTransform = GetManipulatorTransform();
|
||||
|
||||
const float screenToWorldMultiplier = AzToolsFramework::CalculateScreenToWorldMultiplier(
|
||||
AzToolsFramework::GetWorldTransform(m_entityId1).GetTranslation(), m_cameraState);
|
||||
|
||||
// calculate positions for two click and drag motions (moving a linear manipulator)
|
||||
// begin each click in the center of the line of the linear manipulators
|
||||
const auto translationManipulatorStartHoldWorldPosition1 = AzToolsFramework::GetWorldTransform(m_entityId1).GetTranslation() +
|
||||
initialManipulatorTransform->GetBasisZ() * screenToWorldMultiplier;
|
||||
const auto translationManipulatorEndHoldWorldPosition1 =
|
||||
translationManipulatorStartHoldWorldPosition1 + AZ::Vector3::CreateAxisZ(LinearManipulatorZAxisMovement);
|
||||
const auto translationManipulatorStartHoldWorldPosition2 = AzToolsFramework::GetWorldTransform(m_entityId1).GetTranslation() +
|
||||
AZ::Vector3::CreateAxisZ(LinearManipulatorZAxisMovement) - initialManipulatorTransform->GetBasisY() * screenToWorldMultiplier;
|
||||
const auto translationManipulatorEndHoldWorldPosition2 =
|
||||
translationManipulatorStartHoldWorldPosition2 + AZ::Vector3::CreateAxisY(LinearManipulatorYAxisMovement);
|
||||
|
||||
// transform to screen space
|
||||
const auto translationManipulatorStartHoldScreenPosition1 =
|
||||
AzFramework::WorldToScreen(translationManipulatorStartHoldWorldPosition1, m_cameraState);
|
||||
const auto translationManipulatorEndHoldScreenPosition1 =
|
||||
AzFramework::WorldToScreen(translationManipulatorEndHoldWorldPosition1, m_cameraState);
|
||||
const auto translationManipulatorStartHoldScreenPosition2 =
|
||||
AzFramework::WorldToScreen(translationManipulatorStartHoldWorldPosition2, m_cameraState);
|
||||
const auto translationManipulatorEndHoldScreenPosition2 =
|
||||
AzFramework::WorldToScreen(translationManipulatorEndHoldWorldPosition2, m_cameraState);
|
||||
|
||||
m_actionDispatcher->CameraState(m_cameraState)
|
||||
->MousePosition(translationManipulatorStartHoldScreenPosition1)
|
||||
->KeyboardModifierDown(GetParam().m_keyboardModifier)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(translationManipulatorEndHoldScreenPosition1)
|
||||
->MouseLButtonUp()
|
||||
->MousePosition(translationManipulatorStartHoldScreenPosition2)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(translationManipulatorEndHoldScreenPosition2)
|
||||
->MouseLButtonUp();
|
||||
|
||||
const auto expectedEntity2Transform = GetParam().m_firstExpectedEntityTransformAfter;
|
||||
const auto expectedEntity3Transform = GetParam().m_secondExpectedEntityTransformAfter;
|
||||
const auto expectedManipulatorTransform = GetParam().m_expectedManipulatorTransformAfter;
|
||||
|
||||
const auto manipulatorTransformAfter = GetManipulatorTransform();
|
||||
const auto entity2Transform = AzToolsFramework::GetWorldTransform(m_entityId2);
|
||||
const auto entity3Transform = AzToolsFramework::GetWorldTransform(m_entityId3);
|
||||
|
||||
EXPECT_THAT(*manipulatorTransformAfter, IsCloseTolerance(expectedManipulatorTransform, 0.01f));
|
||||
EXPECT_THAT(entity2Transform, IsCloseTolerance(expectedEntity2Transform, 0.01f));
|
||||
EXPECT_THAT(entity3Transform, IsCloseTolerance(expectedEntity3Transform, 0.01f));
|
||||
}
|
||||
|
||||
static const AZ::Transform ExpectedEntity2TransformAfterLocalGroupTranslationManipulatorMotion =
|
||||
AZ::Transform::CreateTranslation(
|
||||
EditorTransformComponentSelectionViewportPickingFixture::Entity2WorldTranslation +
|
||||
AZ::Vector3(0.0f, LinearManipulatorYAxisMovement, LinearManipulatorZAxisMovement)) *
|
||||
Entity2RotationForLocalTranslation;
|
||||
static const AZ::Transform ExpectedEntity3TransformAfterLocalGroupTranslationManipulatorMotion = AZ::Transform::CreateTranslation(
|
||||
EditorTransformComponentSelectionViewportPickingFixture::Entity3WorldTranslation +
|
||||
AZ::Vector3(0.0f, LinearManipulatorYAxisMovement, LinearManipulatorZAxisMovement));
|
||||
// note: as entity has been rotated by 90 degrees about Z in TranslatingMultipleEntitiesWithDifferentModifierCombinations then
|
||||
// LinearManipulatorYAxisMovement is now aligned to the world x-axis
|
||||
static const AZ::Transform ExpectedEntity2TransformAfterLocalIndividualTranslationManipulatorMotion =
|
||||
AZ::Transform::CreateTranslation(
|
||||
EditorTransformComponentSelectionViewportPickingFixture::Entity2WorldTranslation +
|
||||
AZ::Vector3(-LinearManipulatorYAxisMovement, 0.0f, LinearManipulatorZAxisMovement)) *
|
||||
Entity2RotationForLocalTranslation;
|
||||
static const AZ::Transform ExpectedEntity3TransformAfterLocalIndividualTranslationManipulatorMotion = AZ::Transform::CreateTranslation(
|
||||
EditorTransformComponentSelectionViewportPickingFixture::Entity3WorldTranslation +
|
||||
AZ::Vector3(0.0f, LinearManipulatorYAxisMovement, LinearManipulatorZAxisMovement));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
All,
|
||||
EditorTransformComponentSelectionTranslationManipulatorMultipleEntityTestFixtureParam,
|
||||
testing::Values(
|
||||
// this replicates translating a group of entities in local space with no modifiers held (group influence)
|
||||
// manipulator and entity translate
|
||||
ManipulatorOptionsMultiple{ AzToolsFramework::ViewportInteraction::KeyboardModifier::None,
|
||||
ExpectedManipulatorTransformAfterGroupTranslationManipulatorMotion,
|
||||
ExpectedEntity2TransformAfterLocalGroupTranslationManipulatorMotion,
|
||||
ExpectedEntity3TransformAfterLocalGroupTranslationManipulatorMotion },
|
||||
// this replicates translating a group of entities in local space with the alt modifier held
|
||||
// entities move in their own local space (individual influence)
|
||||
ManipulatorOptionsMultiple{ AzToolsFramework::ViewportInteraction::KeyboardModifier::Alt,
|
||||
ExpectedManipulatorTransformAfterGroupTranslationManipulatorMotion,
|
||||
ExpectedEntity2TransformAfterLocalIndividualTranslationManipulatorMotion,
|
||||
ExpectedEntity3TransformAfterLocalIndividualTranslationManipulatorMotion },
|
||||
// this replicates translating a group of entities in world space with the shift modifier held
|
||||
// entities and manipulator move in world space
|
||||
ManipulatorOptionsMultiple{ AzToolsFramework::ViewportInteraction::KeyboardModifier::Shift,
|
||||
ExpectedManipulatorTransformAfterGroupTranslationManipulatorMotion,
|
||||
ExpectedEntity2TransformAfterLocalGroupTranslationManipulatorMotion,
|
||||
ExpectedEntity3TransformAfterLocalGroupTranslationManipulatorMotion },
|
||||
// this replicates translating the manipulator in local space with the ctrl modifier held (entities are unchanged)
|
||||
ManipulatorOptionsMultiple{
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier::Ctrl,
|
||||
ExpectedManipulatorTransformAfterGroupTranslationManipulatorMotion,
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity2WorldTranslation) *
|
||||
Entity2RotationForLocalTranslation,
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity3WorldTranslation) }));
|
||||
|
||||
class EditorTransformComponentSelectionScaleManipulatorMultipleEntityTestFixtureParam
|
||||
: public EditorTransformComponentSelectionManipulatorInteractionTestFixture
|
||||
, public ::testing::WithParamInterface<ManipulatorOptionsMultiple>
|
||||
{
|
||||
};
|
||||
|
||||
static const float LinearManipulatorZAxisMovementScale = 0.5f;
|
||||
|
||||
TEST_P(
|
||||
EditorTransformComponentSelectionScaleManipulatorMultipleEntityTestFixtureParam,
|
||||
ScalingMultipleEntitiesWithDifferentModifierCombinations)
|
||||
{
|
||||
using AzToolsFramework::EditorTransformComponentSelectionRequestBus;
|
||||
|
||||
PositionEntities();
|
||||
|
||||
// move camera up and to the left so it's just above the normal row of entities
|
||||
AzFramework::SetCameraTransform(
|
||||
m_cameraState,
|
||||
AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 15.0f, 10.1f)));
|
||||
|
||||
SetTransformMode(EditorTransformComponentSelectionRequestBus::Events::Mode::Scale);
|
||||
|
||||
AzToolsFramework::SelectEntities({ m_entityId2, m_entityId3 });
|
||||
|
||||
// manipulator should be centered between the two entities
|
||||
const auto initialManipulatorTransform = GetManipulatorTransform();
|
||||
|
||||
const float screenToWorldMultiplier =
|
||||
AzToolsFramework::CalculateScreenToWorldMultiplier(initialManipulatorTransform->GetTranslation(), m_cameraState);
|
||||
|
||||
const auto translationManipulatorStartHoldWorldPosition1 = AzToolsFramework::GetWorldTransform(m_entityId1).GetTranslation() +
|
||||
initialManipulatorTransform->GetBasisZ() * screenToWorldMultiplier;
|
||||
const auto translationManipulatorEndHoldWorldPosition1 =
|
||||
translationManipulatorStartHoldWorldPosition1 + AZ::Vector3::CreateAxisZ(LinearManipulatorZAxisMovementScale);
|
||||
|
||||
// calculate screen space positions
|
||||
const auto scaleManipulatorHoldScreenPosition =
|
||||
AzFramework::WorldToScreen(translationManipulatorStartHoldWorldPosition1, m_cameraState);
|
||||
const auto scaleManipulatorEndHoldScreenPosition =
|
||||
AzFramework::WorldToScreen(translationManipulatorEndHoldWorldPosition1, m_cameraState);
|
||||
|
||||
m_actionDispatcher->CameraState(m_cameraState)
|
||||
->MousePosition(scaleManipulatorHoldScreenPosition)
|
||||
->KeyboardModifierDown(GetParam().m_keyboardModifier)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(scaleManipulatorEndHoldScreenPosition)
|
||||
->MouseLButtonUp();
|
||||
|
||||
const auto expectedEntity2Transform = GetParam().m_firstExpectedEntityTransformAfter;
|
||||
const auto expectedEntity3Transform = GetParam().m_secondExpectedEntityTransformAfter;
|
||||
const auto expectedManipulatorTransform = GetParam().m_expectedManipulatorTransformAfter;
|
||||
|
||||
const auto manipulatorTransformAfter = GetManipulatorTransform();
|
||||
const auto entity2Transform = AzToolsFramework::GetWorldTransform(m_entityId2);
|
||||
const auto entity3Transform = AzToolsFramework::GetWorldTransform(m_entityId3);
|
||||
|
||||
EXPECT_THAT(*manipulatorTransformAfter, IsCloseTolerance(expectedManipulatorTransform, 0.01f));
|
||||
EXPECT_THAT(entity2Transform, IsCloseTolerance(expectedEntity2Transform, 0.01f));
|
||||
EXPECT_THAT(entity3Transform, IsCloseTolerance(expectedEntity3Transform, 0.01f));
|
||||
}
|
||||
|
||||
static const AZ::Transform ExpectedEntity2TransformAfterLocalGroupScaleManipulatorMotion =
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity2WorldTranslation) *
|
||||
AZ::Transform::CreateTranslation(AZ::Vector3(0.0f, -1.0f, 0.0f)) *
|
||||
AZ::Transform::CreateUniformScale(LinearManipulatorZAxisMovement);
|
||||
static const AZ::Transform ExpectedEntity3TransformAfterLocalGroupScaleManipulatorMotion =
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity3WorldTranslation) *
|
||||
AZ::Transform::CreateTranslation(AZ::Vector3(0.0f, 1.0f, 0.0f)) * AZ::Transform::CreateUniformScale(LinearManipulatorZAxisMovement);
|
||||
static const AZ::Transform ExpectedEntity2TransformAfterLocalIndividualScaleManipulatorMotion =
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity2WorldTranslation) *
|
||||
AZ::Transform::CreateUniformScale(LinearManipulatorZAxisMovement);
|
||||
static const AZ::Transform ExpectedEntity3TransformAfterLocalIndividualScaleManipulatorMotion =
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity3WorldTranslation) *
|
||||
AZ::Transform::CreateUniformScale(LinearManipulatorZAxisMovement);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
All,
|
||||
EditorTransformComponentSelectionScaleManipulatorMultipleEntityTestFixtureParam,
|
||||
testing::Values(
|
||||
// this replicates scaling a group of entities in local space with no modifiers held
|
||||
// entities scale relative to manipulator pivot
|
||||
ManipulatorOptionsMultiple{ AzToolsFramework::ViewportInteraction::KeyboardModifier::None,
|
||||
AZ::Transform::CreateTranslation(AggregateManipulatorPositionWithEntity2and3Selected),
|
||||
ExpectedEntity2TransformAfterLocalGroupScaleManipulatorMotion,
|
||||
ExpectedEntity3TransformAfterLocalGroupScaleManipulatorMotion },
|
||||
// this replicates scaling a group of entities in local space with the alt modifier held
|
||||
// entities scale about their own pivot
|
||||
ManipulatorOptionsMultiple{ AzToolsFramework::ViewportInteraction::KeyboardModifier::Alt,
|
||||
AZ::Transform::CreateTranslation(AggregateManipulatorPositionWithEntity2and3Selected),
|
||||
ExpectedEntity2TransformAfterLocalIndividualScaleManipulatorMotion,
|
||||
ExpectedEntity3TransformAfterLocalIndividualScaleManipulatorMotion },
|
||||
// this replicates scaling a group of entities in world space with the shift modifier held
|
||||
// entities scale relative to manipulator pivot in world space
|
||||
ManipulatorOptionsMultiple{ AzToolsFramework::ViewportInteraction::KeyboardModifier::Shift,
|
||||
AZ::Transform::CreateTranslation(AggregateManipulatorPositionWithEntity2and3Selected),
|
||||
ExpectedEntity2TransformAfterLocalGroupScaleManipulatorMotion,
|
||||
ExpectedEntity3TransformAfterLocalGroupScaleManipulatorMotion },
|
||||
// this has no effect (entities and manipulator are unchanged)
|
||||
ManipulatorOptionsMultiple{
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier::Ctrl,
|
||||
AZ::Transform::CreateTranslation(AggregateManipulatorPositionWithEntity2and3Selected),
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity2WorldTranslation),
|
||||
AZ::Transform::CreateTranslation(EditorTransformComponentSelectionViewportPickingFixture::Entity3WorldTranslation) }));
|
||||
|
||||
using EditorTransformComponentSelectionManipulatorTestFixture =
|
||||
IndirectCallManipulatorViewportInteractionFixtureMixin<EditorTransformComponentSelectionFixture>;
|
||||
|
||||
@@ -1661,7 +2211,7 @@ namespace UnitTest
|
||||
All,
|
||||
EditorTransformComponentSelectionSingleEntityPivotAndOverrideFixture,
|
||||
testing::Values(
|
||||
ReferenceFrameWithOrientation{ AzToolsFramework::ReferenceFrame::Local, ChildExpectedPivotLocalOrientationInWorldSpace },
|
||||
ReferenceFrameWithOrientation{ AzToolsFramework::ReferenceFrame::Local, PivotOverrideLocalOrientationInWorldSpace },
|
||||
ReferenceFrameWithOrientation{ AzToolsFramework::ReferenceFrame::Parent, PivotOverrideLocalOrientationInWorldSpace },
|
||||
ReferenceFrameWithOrientation{ AzToolsFramework::ReferenceFrame::World, AZ::Quaternion::CreateIdentity() }));
|
||||
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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 <AzTest/AzTest.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class EditorFocusModeTests
|
||||
: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
m_app.Start(m_descriptor);
|
||||
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
|
||||
GenerateTestHierarchy();
|
||||
}
|
||||
|
||||
void GenerateTestHierarchy()
|
||||
{
|
||||
/*
|
||||
* City
|
||||
* |_ Street
|
||||
* |_ Car
|
||||
* | |_ Passenger
|
||||
* |_ SportsCar
|
||||
* |_ Passenger
|
||||
*/
|
||||
|
||||
m_entityMap["cityId"] = CreateEditorEntity("City", AZ::EntityId());
|
||||
m_entityMap["streetId"] = CreateEditorEntity("Street", m_entityMap["cityId"]);
|
||||
m_entityMap["carId"] = CreateEditorEntity("Car", m_entityMap["streetId"]);
|
||||
m_entityMap["passengerId1"] = CreateEditorEntity("Passenger", m_entityMap["carId"]);
|
||||
m_entityMap["sportsCarId"] = CreateEditorEntity("SportsCar", m_entityMap["streetId"]);
|
||||
m_entityMap["passengerId2"] = CreateEditorEntity("Passenger", m_entityMap["sportsCarId"]);
|
||||
}
|
||||
|
||||
AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId)
|
||||
{
|
||||
AZ::Entity* entity = nullptr;
|
||||
UnitTest::CreateDefaultEditorEntity(name, &entity);
|
||||
|
||||
// Parent
|
||||
AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId);
|
||||
|
||||
return entity->GetId();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_app.Stop();
|
||||
}
|
||||
|
||||
UnitTest::ToolsTestApplication m_app{ "EditorFocusModeTests" };
|
||||
AZ::ComponentApplication::Descriptor m_descriptor;
|
||||
AZStd::unordered_map<AZStd::string, AZ::EntityId> m_entityMap;
|
||||
};
|
||||
|
||||
TEST_F(EditorFocusModeTests, EditorFocusModeTests_SetFocus)
|
||||
{
|
||||
FocusModeInterface* focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
EXPECT_TRUE(focusModeInterface != nullptr);
|
||||
|
||||
focusModeInterface->SetFocusRoot(m_entityMap["carId"]);
|
||||
EXPECT_EQ(focusModeInterface->GetFocusRoot(), m_entityMap["carId"]);
|
||||
|
||||
focusModeInterface->ClearFocusRoot();
|
||||
EXPECT_EQ(focusModeInterface->GetFocusRoot(), AZ::EntityId());
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeTests, EditorFocusModeTests_IsInFocusSubTree)
|
||||
{
|
||||
FocusModeInterface* focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
EXPECT_TRUE(focusModeInterface != nullptr);
|
||||
|
||||
focusModeInterface->ClearFocusRoot();
|
||||
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
|
||||
|
||||
focusModeInterface->SetFocusRoot(m_entityMap["streetId"]);
|
||||
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
|
||||
|
||||
focusModeInterface->SetFocusRoot(m_entityMap["carId"]);
|
||||
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), false);
|
||||
|
||||
focusModeInterface->SetFocusRoot(m_entityMap["passengerId2"]);
|
||||
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
|
||||
|
||||
focusModeInterface->ClearFocusRoot();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <Prefab/PrefabTestFixture.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class PrefabFocusTests
|
||||
: public PrefabTestFixture
|
||||
{
|
||||
protected:
|
||||
void GenerateTestHierarchy()
|
||||
{
|
||||
/*
|
||||
* City (Prefab Container)
|
||||
* |_ City
|
||||
* |_ Street (Prefab Container)
|
||||
* |_ Car (Prefab Container)
|
||||
* | |_ Passenger
|
||||
* |_ SportsCar (Prefab Container)
|
||||
* |_ Passenger
|
||||
*/
|
||||
|
||||
m_entityMap["passenger1"] = CreateEntity("Passenger1");
|
||||
m_entityMap["passenger2"] = CreateEntity("Passenger2");
|
||||
m_entityMap["city"] = CreateEntity("City");
|
||||
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded,
|
||||
AzToolsFramework::EntityList{ m_entityMap["passenger1"], m_entityMap["passenger2"], m_entityMap["city"] });
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> carInstance =
|
||||
m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger1"] }, {}, "test/car");
|
||||
ASSERT_TRUE(carInstance);
|
||||
m_instanceMap["car"] = carInstance.get();
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> sportsCarInstance =
|
||||
m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger2"] }, {}, "test/sportsCar");
|
||||
ASSERT_TRUE(sportsCarInstance);
|
||||
m_instanceMap["sportsCar"] = sportsCarInstance.get();
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> streetInstance =
|
||||
m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(carInstance), AZStd::move(sportsCarInstance) ), "test/street");
|
||||
ASSERT_TRUE(streetInstance);
|
||||
m_instanceMap["street"] = streetInstance.get();
|
||||
|
||||
m_rootInstance =
|
||||
m_prefabSystemComponent->CreatePrefab({ m_entityMap["city"] }, MakeInstanceList(AZStd::move(streetInstance)), "test/city");
|
||||
ASSERT_TRUE(m_rootInstance);
|
||||
m_instanceMap["city"] = m_rootInstance.get();
|
||||
}
|
||||
|
||||
AZStd::unordered_map<AZStd::string, AZ::Entity*> m_entityMap;
|
||||
AZStd::unordered_map<AZStd::string, Instance*> m_instanceMap;
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> m_rootInstance;
|
||||
};
|
||||
|
||||
TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab)
|
||||
{
|
||||
GenerateTestHierarchy();
|
||||
|
||||
PrefabFocusInterface* prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
|
||||
EXPECT_TRUE(prefabFocusInterface != nullptr);
|
||||
|
||||
// Verify FocusOnOwningPrefab works when passing the container entity of the root prefab.
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId());
|
||||
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId());
|
||||
|
||||
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
|
||||
EXPECT_TRUE(instance.has_value());
|
||||
EXPECT_EQ(&instance->get(), m_instanceMap["city"]);
|
||||
}
|
||||
|
||||
// Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab.
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["city"]->GetId());
|
||||
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId());
|
||||
|
||||
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
|
||||
EXPECT_TRUE(instance.has_value());
|
||||
EXPECT_EQ(&instance->get(), m_instanceMap["city"]);
|
||||
}
|
||||
|
||||
// Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab.
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["car"]->GetContainerEntityId());
|
||||
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId());
|
||||
|
||||
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
|
||||
EXPECT_TRUE(instance.has_value());
|
||||
EXPECT_EQ(&instance->get(), m_instanceMap["car"]);
|
||||
}
|
||||
|
||||
// Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab.
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["passenger1"]->GetId());
|
||||
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId());
|
||||
|
||||
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
|
||||
EXPECT_TRUE(instance.has_value());
|
||||
EXPECT_EQ(&instance->get(), m_instanceMap["car"]);
|
||||
}
|
||||
|
||||
// Verify FocusOnOwningPrefab points to the root prefab when the focus is cleared.
|
||||
{
|
||||
AzToolsFramework::PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
|
||||
AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
|
||||
AzToolsFramework::Prefab::InstanceOptionalReference rootPrefabInstance =
|
||||
prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
|
||||
EXPECT_TRUE(rootPrefabInstance.has_value());
|
||||
|
||||
prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId());
|
||||
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), rootPrefabInstance->get().GetTemplateId());
|
||||
|
||||
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
|
||||
EXPECT_TRUE(instance.has_value());
|
||||
EXPECT_EQ(&instance->get(), &rootPrefabInstance->get());
|
||||
}
|
||||
|
||||
m_rootInstance.release();
|
||||
}
|
||||
|
||||
TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused)
|
||||
{
|
||||
GenerateTestHierarchy();
|
||||
|
||||
PrefabFocusInterface* prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
|
||||
EXPECT_TRUE(prefabFocusInterface != nullptr);
|
||||
|
||||
// Verify IsOwningPrefabBeingFocused returns true for all entities in a focused prefab (container/nested)
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId());
|
||||
|
||||
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId()));
|
||||
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId()));
|
||||
}
|
||||
|
||||
// Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (ancestors/descendants)
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["street"]->GetContainerEntityId());
|
||||
|
||||
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["street"]->GetContainerEntityId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId()));
|
||||
}
|
||||
|
||||
// Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (siblings)
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["sportsCar"]->GetContainerEntityId());
|
||||
|
||||
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["sportsCar"]->GetContainerEntityId()));
|
||||
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger2"]->GetId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId()));
|
||||
}
|
||||
|
||||
m_rootInstance.release();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,8 +6,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Math/Matrix3x4.h>
|
||||
#include <AzCore/Math/Matrix3x3.h>
|
||||
#include <AzCore/Math/Matrix3x4.h>
|
||||
#include <AzCore/Math/Matrix4x4.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Math/VectorConversions.h>
|
||||
@@ -20,18 +20,17 @@
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
// transform a point from normalized device coordinates to world space, and then from world space back to normalized device coordinates
|
||||
AZ::Vector2 ScreenNDCToWorldToScreenNDC(
|
||||
const AZ::Vector2& ndcPoint, const AzFramework::CameraState& cameraState)
|
||||
// transform a point from normalized device coordinates to world space, and then from world space back to normalized device coordinates
|
||||
AZ::Vector2 ScreenNdcToWorldToScreenNdc(const AZ::Vector2& ndcPoint, const AzFramework::CameraState& cameraState)
|
||||
{
|
||||
const auto worldResult = AzFramework::ScreenNDCToWorld(ndcPoint, InverseCameraView(cameraState), InverseCameraProjection(cameraState));
|
||||
const auto ndcResult = AzFramework::WorldToScreenNDC(worldResult, CameraView(cameraState), CameraProjection(cameraState));
|
||||
const auto worldResult =
|
||||
AzFramework::ScreenNdcToWorld(ndcPoint, InverseCameraView(cameraState), InverseCameraProjection(cameraState));
|
||||
const auto ndcResult = AzFramework::WorldToScreenNdc(worldResult, CameraView(cameraState), CameraProjection(cameraState));
|
||||
return AZ::Vector3ToVector2(ndcResult);
|
||||
}
|
||||
|
||||
// transform a point from screen space to world space, and then from world space back to screen space
|
||||
AzFramework::ScreenPoint ScreenToWorldToScreen(
|
||||
const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState)
|
||||
AzFramework::ScreenPoint ScreenToWorldToScreen(const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState)
|
||||
{
|
||||
const auto worldResult = AzFramework::ScreenToWorld(screenPoint, cameraState);
|
||||
return AzFramework::WorldToScreen(worldResult, cameraState);
|
||||
@@ -47,25 +46,25 @@ namespace UnitTest
|
||||
|
||||
const auto cameraState = AzFramework::CreateIdentityDefaultCamera(cameraPosition, screenDimensions);
|
||||
{
|
||||
const auto expectedScreenPoint = ScreenPoint{600, 450};
|
||||
const auto expectedScreenPoint = ScreenPoint{ 600, 450 };
|
||||
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, cameraState);
|
||||
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
|
||||
}
|
||||
|
||||
{
|
||||
const auto expectedScreenPoint = ScreenPoint{400, 300};
|
||||
const auto expectedScreenPoint = ScreenPoint{ 400, 300 };
|
||||
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, cameraState);
|
||||
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
|
||||
}
|
||||
|
||||
{
|
||||
const auto expectedScreenPoint = ScreenPoint{0, 0};
|
||||
const auto expectedScreenPoint = ScreenPoint{ 0, 0 };
|
||||
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, cameraState);
|
||||
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
|
||||
}
|
||||
|
||||
{
|
||||
const auto expectedScreenPoint = ScreenPoint{800, 600};
|
||||
const auto expectedScreenPoint = ScreenPoint{ 800, 600 };
|
||||
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, cameraState);
|
||||
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
|
||||
}
|
||||
@@ -81,7 +80,7 @@ namespace UnitTest
|
||||
|
||||
const auto cameraState = AzFramework::CreateDefaultCamera(cameraTransform, screenDimensions);
|
||||
|
||||
const auto expectedScreenPoint = ScreenPoint{200, 300};
|
||||
const auto expectedScreenPoint = ScreenPoint{ 200, 300 };
|
||||
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, cameraState);
|
||||
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
|
||||
}
|
||||
@@ -93,46 +92,46 @@ namespace UnitTest
|
||||
using AzFramework::ScreenPoint;
|
||||
|
||||
const auto screenDimensions = AZ::Vector2(800.0f, 600.0f);
|
||||
const auto cameraTransform = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 0.0f, 0.0f)) *
|
||||
AZ::Transform::CreateRotationZ(AZ::DegToRad(-90.0f));
|
||||
const auto cameraTransform =
|
||||
AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 0.0f, 0.0f)) * AZ::Transform::CreateRotationZ(AZ::DegToRad(-90.0f));
|
||||
|
||||
const auto cameraState = AzFramework::CreateDefaultCamera(cameraTransform, screenDimensions);
|
||||
|
||||
const auto worldResult = AzFramework::ScreenToWorld(ScreenPoint{400, 300}, cameraState);
|
||||
const auto worldResult = AzFramework::ScreenToWorld(ScreenPoint{ 400, 300 }, cameraState);
|
||||
EXPECT_THAT(worldResult, IsClose(AZ::Vector3(10.1f, 0.0f, 0.0f)));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NDC tests
|
||||
TEST(ViewportScreen, WorldToScreenNDCAndScreenNDCToWorldReturnsTheSameValueIdentityCameraOffsetFromOrigin)
|
||||
{
|
||||
using NdcPoint = AZ::Vector2;
|
||||
|
||||
|
||||
const auto screenDimensions = AZ::Vector2(800.0f, 600.0f);
|
||||
const auto cameraPosition = AZ::Vector3::CreateAxisY(-10.0f);
|
||||
|
||||
const auto cameraState = AzFramework::CreateIdentityDefaultCamera(cameraPosition, screenDimensions);
|
||||
{
|
||||
const auto expectedNdcPoint = NdcPoint{0.75f, 0.75f};
|
||||
const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState);
|
||||
const auto expectedNdcPoint = NdcPoint{ 0.75f, 0.75f };
|
||||
const auto resultNdcPoint = ScreenNdcToWorldToScreenNdc(expectedNdcPoint, cameraState);
|
||||
EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint));
|
||||
}
|
||||
|
||||
{
|
||||
const auto expectedNdcPoint = NdcPoint{0.5f, 0.5f};
|
||||
const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState);
|
||||
const auto expectedNdcPoint = NdcPoint{ 0.5f, 0.5f };
|
||||
const auto resultNdcPoint = ScreenNdcToWorldToScreenNdc(expectedNdcPoint, cameraState);
|
||||
EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint));
|
||||
}
|
||||
|
||||
{
|
||||
const auto expectedNdcPoint = NdcPoint{0.0f, 0.0f};
|
||||
const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState);
|
||||
const auto expectedNdcPoint = NdcPoint{ 0.0f, 0.0f };
|
||||
const auto resultNdcPoint = ScreenNdcToWorldToScreenNdc(expectedNdcPoint, cameraState);
|
||||
EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint));
|
||||
}
|
||||
|
||||
{
|
||||
const auto expectedNdcPoint = NdcPoint{1.0f, 1.0f};
|
||||
const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState);
|
||||
const auto expectedNdcPoint = NdcPoint{ 1.0f, 1.0f };
|
||||
const auto resultNdcPoint = ScreenNdcToWorldToScreenNdc(expectedNdcPoint, cameraState);
|
||||
EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint));
|
||||
}
|
||||
}
|
||||
@@ -147,8 +146,8 @@ namespace UnitTest
|
||||
|
||||
const auto cameraState = AzFramework::CreateDefaultCamera(cameraTransform, screenDimensions);
|
||||
|
||||
const auto expectedNdcPoint = NdcPoint{0.25f, 0.5f};
|
||||
const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState);
|
||||
const auto expectedNdcPoint = NdcPoint{ 0.25f, 0.5f };
|
||||
const auto resultNdcPoint = ScreenNdcToWorldToScreenNdc(expectedNdcPoint, cameraState);
|
||||
EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint));
|
||||
}
|
||||
|
||||
@@ -159,12 +158,13 @@ namespace UnitTest
|
||||
using NdcPoint = AZ::Vector2;
|
||||
|
||||
const auto screenDimensions = AZ::Vector2(800.0f, 600.0f);
|
||||
const auto cameraTransform = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 0.0f, 0.0f)) *
|
||||
AZ::Transform::CreateRotationZ(AZ::DegToRad(-90.0f));
|
||||
const auto cameraTransform =
|
||||
AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 0.0f, 0.0f)) * AZ::Transform::CreateRotationZ(AZ::DegToRad(-90.0f));
|
||||
|
||||
const auto cameraState = AzFramework::CreateDefaultCamera(cameraTransform, screenDimensions);
|
||||
|
||||
const auto worldResult = AzFramework::ScreenNDCToWorld(NdcPoint{0.5f, 0.5f}, InverseCameraView(cameraState), InverseCameraProjection(cameraState));
|
||||
const auto worldResult =
|
||||
AzFramework::ScreenNdcToWorld(NdcPoint{ 0.5f, 0.5f }, InverseCameraView(cameraState), InverseCameraProjection(cameraState));
|
||||
EXPECT_THAT(worldResult, IsClose(AZ::Vector3(10.1f, 0.0f, 0.0f)));
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ namespace UnitTest
|
||||
using AzFramework::ScreenPoint;
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
const ScreenVector screenVector = ScreenPoint{100, 200} - ScreenPoint{10, 20};
|
||||
const ScreenVector screenVector = ScreenPoint{ 100, 200 } - ScreenPoint{ 10, 20 };
|
||||
EXPECT_EQ(screenVector, ScreenVector(90, 180));
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace UnitTest
|
||||
using AzFramework::ScreenPoint;
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
const ScreenPoint screenPoint = ScreenPoint{100, 200} + ScreenVector{50, 25};
|
||||
const ScreenPoint screenPoint = ScreenPoint{ 100, 200 } + ScreenVector{ 50, 25 };
|
||||
EXPECT_EQ(screenPoint, ScreenPoint(150, 225));
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace UnitTest
|
||||
using AzFramework::ScreenPoint;
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
const ScreenPoint screenPoint = ScreenPoint{120, 200} - ScreenVector{50, 20};
|
||||
const ScreenPoint screenPoint = ScreenPoint{ 120, 200 } - ScreenVector{ 50, 20 };
|
||||
EXPECT_EQ(screenPoint, ScreenPoint(70, 180));
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace UnitTest
|
||||
using AzFramework::ScreenPoint;
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
const ScreenVector screenVector = ScreenVector{100, 200} + ScreenVector{50, 25};
|
||||
const ScreenVector screenVector = ScreenVector{ 100, 200 } + ScreenVector{ 50, 25 };
|
||||
EXPECT_EQ(screenVector, ScreenVector(150, 225));
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ namespace UnitTest
|
||||
using AzFramework::ScreenPoint;
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
const ScreenVector screenVector = ScreenVector{100, 200} - ScreenVector{50, 25};
|
||||
const ScreenVector screenVector = ScreenVector{ 100, 200 } - ScreenVector{ 50, 25 };
|
||||
EXPECT_EQ(screenVector, ScreenVector(50, 175));
|
||||
}
|
||||
|
||||
@@ -220,8 +220,8 @@ namespace UnitTest
|
||||
using AzFramework::ScreenPoint;
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
const ScreenPoint screenPoint = ScreenPoint{100, 200};
|
||||
const ScreenVector screenVector = ScreenVector{50, 25};
|
||||
const ScreenPoint screenPoint = ScreenPoint{ 100, 200 };
|
||||
const ScreenVector screenVector = ScreenVector{ 50, 25 };
|
||||
|
||||
const AZ::Vector2 fromScreenPoint = AzFramework::Vector2FromScreenPoint(screenPoint);
|
||||
const AZ::Vector2 fromScreenVector = AzFramework::Vector2FromScreenVector(screenVector);
|
||||
@@ -295,6 +295,58 @@ namespace UnitTest
|
||||
EXPECT_NEAR(AzFramework::ScreenVectorLength(ScreenVector(12, 15)), 19.20937f, 0.001f);
|
||||
}
|
||||
|
||||
TEST(ViewportScreen, ScreenVectorTransformedByScalarUpwards)
|
||||
{
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
auto screenVector = ScreenVector(5, 10);
|
||||
auto scaledScreenVector = screenVector * 2.0f;
|
||||
|
||||
EXPECT_EQ(scaledScreenVector, ScreenVector(10, 20));
|
||||
}
|
||||
|
||||
TEST(ViewportScreen, ScreenVectorTransformedByScalarWithRounding)
|
||||
{
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
auto screenVector = ScreenVector(1, 6);
|
||||
auto scaledScreenVector = screenVector * 0.1f;
|
||||
|
||||
// value less than 0.5 rounds down, greater than or equal to 0.5 rounds up
|
||||
EXPECT_EQ(scaledScreenVector, ScreenVector(0, 1));
|
||||
}
|
||||
|
||||
TEST(ViewportScreen, ScreenVectorTransformedByScalarWithRoundingAtHalfwayBoundary)
|
||||
{
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
auto screenVector = ScreenVector(5, 10);
|
||||
auto scaledScreenVector = screenVector * 0.1f;
|
||||
|
||||
// value less than 0.5 rounds down, greater than or equal to 0.5 rounds up
|
||||
EXPECT_EQ(scaledScreenVector, ScreenVector(1, 1));
|
||||
}
|
||||
|
||||
TEST(ViewportScreen, ScreenVectorTransformedByScalarDownwards)
|
||||
{
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
auto screenVector = ScreenVector(6, 12);
|
||||
auto scaledScreenVector = screenVector * 0.5f;
|
||||
|
||||
EXPECT_EQ(scaledScreenVector, ScreenVector(3, 6));
|
||||
}
|
||||
|
||||
TEST(ViewportScreen, ScreenVectorTransformedByScalarInplace)
|
||||
{
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
auto screenVector = ScreenVector(13, 37);
|
||||
screenVector *= 10.0f;
|
||||
|
||||
EXPECT_EQ(screenVector, ScreenVector(130, 370));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Other tests
|
||||
TEST(ViewportScreen, CanGetCameraTransformFromCameraViewAndBack)
|
||||
|
||||
@@ -34,6 +34,7 @@ set(FILES
|
||||
EntityTestbed.h
|
||||
FileFunc.cpp
|
||||
FingerprintingTests.cpp
|
||||
FocusMode/EditorFocusModeTests.cpp
|
||||
GenericComponentWrapperTest.cpp
|
||||
InstanceDataHierarchy.cpp
|
||||
IntegerPrimtitiveTestConfig.h
|
||||
@@ -50,6 +51,7 @@ set(FILES
|
||||
Prefab/Benchmark/PrefabLoadBenchmarks.cpp
|
||||
Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp
|
||||
Prefab/Benchmark/SpawnableCreateBenchmarks.cpp
|
||||
Prefab/PrefabFocus/PrefabFocusTests.cpp
|
||||
Prefab/MockPrefabFileIOActionValidator.cpp
|
||||
Prefab/MockPrefabFileIOActionValidator.h
|
||||
Prefab/PrefabDuplicateTests.cpp
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user