merging latest development
Signed-off-by: kberg-amzn <karlberg@amazon.com>
This commit is contained in:
@@ -140,9 +140,6 @@
|
||||
<property name="horizontalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@@ -201,6 +198,11 @@
|
||||
<header>AzToolsFramework/AssetBrowser/Search/SearchWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::TableView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>AzQtComponents/Components/Widgets/TableView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzToolsFramework::AssetBrowser::AssetBrowserTreeView</class>
|
||||
<extends>QTreeView</extends>
|
||||
@@ -214,7 +216,7 @@
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzToolsFramework::AssetBrowser::AssetBrowserTableView</class>
|
||||
<extends>QTableView</extends>
|
||||
<extends>AzQtComponents::TableView</extends>
|
||||
<header>AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
|
||||
@@ -8,11 +8,21 @@
|
||||
|
||||
#include "QtEditorApplication.h"
|
||||
|
||||
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
#include <AzFramework/API/ApplicationAPI_Linux.h>
|
||||
#endif
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
bool EditorQtApplication::nativeEventFilter(const QByteArray& , void* , long* )
|
||||
bool EditorQtApplication::nativeEventFilter([[maybe_unused]] const QByteArray& eventType, void* message, long*)
|
||||
{
|
||||
// TODO_KDAB_LINUX
|
||||
if (GetIEditor()->IsInGameMode())
|
||||
{
|
||||
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
AzFramework::LinuxXcbEventHandlerBus::Broadcast(&AzFramework::LinuxXcbEventHandler::HandleXcbEvent, static_cast<xcb_generic_event_t*>(message));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,14 @@ namespace EditorInternal
|
||||
: ToolsApplication(argc, argv)
|
||||
{
|
||||
EditorToolsApplicationRequests::Bus::Handler::BusConnect();
|
||||
AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusConnect();
|
||||
AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
EditorToolsApplication::~EditorToolsApplication()
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusDisconnect();
|
||||
EditorToolsApplicationRequests::Bus::Handler::BusDisconnect();
|
||||
Stop();
|
||||
}
|
||||
@@ -48,7 +52,6 @@ namespace EditorInternal
|
||||
return m_StartupAborted;
|
||||
}
|
||||
|
||||
|
||||
void EditorToolsApplication::RegisterCoreComponents()
|
||||
{
|
||||
AzToolsFramework::ToolsApplication::RegisterCoreComponents();
|
||||
@@ -274,5 +277,14 @@ namespace EditorInternal
|
||||
Exit();
|
||||
}
|
||||
|
||||
}
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifiers EditorToolsApplication::QueryKeyboardModifiers()
|
||||
{
|
||||
return AzToolsFramework::ViewportInteraction::BuildKeyboardModifiers(QGuiApplication::queryKeyboardModifiers());
|
||||
}
|
||||
|
||||
AZStd::chrono::milliseconds EditorToolsApplication::EditorViewportInputTimeNow()
|
||||
{
|
||||
const auto now = AZStd::chrono::high_resolution_clock::now();
|
||||
return AZStd::chrono::time_point_cast<AZStd::chrono::milliseconds>(now).time_since_epoch();
|
||||
}
|
||||
} // namespace EditorInternal
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
|
||||
#include "Core/EditorMetricsPlainTextNameRegistration.h"
|
||||
#include "EditorToolsApplicationAPI.h"
|
||||
@@ -19,6 +21,8 @@ namespace EditorInternal
|
||||
class EditorToolsApplication
|
||||
: public AzToolsFramework::ToolsApplication
|
||||
, public EditorToolsApplicationRequests::Bus::Handler
|
||||
, public AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler
|
||||
, public AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
EditorToolsApplication(int* argc, char*** argv);
|
||||
@@ -44,6 +48,12 @@ namespace EditorInternal
|
||||
void CreateReflectionManager() override;
|
||||
void Reflect(AZ::ReflectContext* context) override;
|
||||
|
||||
// EditorModifierKeyRequestBus overrides ...
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifiers QueryKeyboardModifiers() override;
|
||||
|
||||
// EditorViewportInputTimeNowRequestBus overrides ...
|
||||
AZStd::chrono::milliseconds EditorViewportInputTimeNow() override;
|
||||
|
||||
protected:
|
||||
// From EditorToolsApplicationRequests
|
||||
bool OpenLevel(AZStd::string_view levelName) override;
|
||||
|
||||
@@ -744,11 +744,15 @@ void EditorViewportWidget::RenderAll()
|
||||
{
|
||||
namespace AztfVi = AzToolsFramework::ViewportInteraction;
|
||||
|
||||
AztfVi::KeyboardModifiers keyboardModifiers;
|
||||
AztfVi::EditorModifierKeyRequestBus::BroadcastResult(
|
||||
keyboardModifiers, &AztfVi::EditorModifierKeyRequestBus::Events::QueryKeyboardModifiers);
|
||||
|
||||
m_debugDisplay->DepthTestOff();
|
||||
m_manipulatorManager->DrawManipulators(
|
||||
*m_debugDisplay, GetCameraState(),
|
||||
BuildMouseInteractionInternal(
|
||||
AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())), QueryKeyboardModifiers(),
|
||||
AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())), keyboardModifiers,
|
||||
BuildMousePick(WidgetToViewport(mapFromGlobal(QCursor::pos())))));
|
||||
m_debugDisplay->DepthTestOn();
|
||||
}
|
||||
@@ -959,12 +963,13 @@ QWidget* EditorViewportWidget::GetWidgetForViewportContextMenu()
|
||||
|
||||
bool EditorViewportWidget::ShowingWorldSpace()
|
||||
{
|
||||
return QueryKeyboardModifiers().Shift();
|
||||
}
|
||||
namespace AztfVi = AzToolsFramework::ViewportInteraction;
|
||||
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifiers EditorViewportWidget::QueryKeyboardModifiers()
|
||||
{
|
||||
return AzToolsFramework::ViewportInteraction::BuildKeyboardModifiers(QGuiApplication::queryKeyboardModifiers());
|
||||
AztfVi::KeyboardModifiers keyboardModifiers;
|
||||
AztfVi::EditorModifierKeyRequestBus::BroadcastResult(
|
||||
keyboardModifiers, &AztfVi::EditorModifierKeyRequestBus::Events::QueryKeyboardModifiers);
|
||||
|
||||
return keyboardModifiers.Shift();
|
||||
}
|
||||
|
||||
void EditorViewportWidget::SetViewportId(int id)
|
||||
@@ -1039,7 +1044,6 @@ void EditorViewportWidget::ConnectViewportInteractionRequestBus()
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler::BusConnect(GetViewportId());
|
||||
AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusConnect(GetViewportId());
|
||||
AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusConnect();
|
||||
m_viewportUi.ConnectViewportUiBus(GetViewportId());
|
||||
|
||||
AzFramework::InputSystemCursorConstraintRequestBus::Handler::BusConnect();
|
||||
@@ -1050,7 +1054,6 @@ void EditorViewportWidget::DisconnectViewportInteractionRequestBus()
|
||||
AzFramework::InputSystemCursorConstraintRequestBus::Handler::BusDisconnect();
|
||||
|
||||
m_viewportUi.DisconnectViewportUiBus();
|
||||
AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
@@ -92,7 +92,6 @@ class SANDBOX_API EditorViewportWidget final
|
||||
, private AzFramework::InputSystemCursorConstraintRequestBus::Handler
|
||||
, private AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler
|
||||
, private AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler
|
||||
, private AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler
|
||||
, private AzFramework::AssetCatalogEventBus::Handler
|
||||
, private AZ::RPI::SceneNotificationBus::Handler
|
||||
{
|
||||
@@ -212,9 +211,6 @@ private:
|
||||
// EditorEntityViewportInteractionRequestBus overrides ...
|
||||
void FindVisibleEntities(AZStd::vector<AZ::EntityId>& visibleEntities) override;
|
||||
|
||||
// EditorModifierKeyRequestBus overrides ...
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifiers QueryKeyboardModifiers() override;
|
||||
|
||||
// Camera::EditorCameraRequestBus overrides ...
|
||||
void SetViewFromEntityPerspective(const AZ::EntityId& entityId) override;
|
||||
void SetViewAndMovementLockFromEntityPerspective(const AZ::EntityId& entityId, bool lockCameraMovement) override;
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
#define CRYINCLUDE_EDITOR_INCLUDE_IEDITORCLASSFACTORY_H
|
||||
#pragma once
|
||||
|
||||
#include <CryCommon/platform.h>
|
||||
#include <vector>
|
||||
#include <QtCore/QString>
|
||||
#include <AzCore/Math/Guid.h>
|
||||
|
||||
#define DEFINE_UUID(l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
static const GUID uuid() { return { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }; }
|
||||
@@ -34,7 +36,7 @@ struct IUnknown
|
||||
#endif
|
||||
#define __uuidof(T) T::uuid()
|
||||
|
||||
#if defined(AZ_PLATFORM_LINUX)
|
||||
#if defined(AZ_PLATFORM_LINUX) || defined(AZ_PLATFORM_MAC)
|
||||
|
||||
# ifndef _REFGUID_DEFINED
|
||||
# define _REFGUID_DEFINED
|
||||
@@ -65,7 +67,7 @@ enum
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // defined(AZ_PLATFORM_LINUX)
|
||||
#endif // defined(AZ_PLATFORM_LINUX) || defined(AZ_PLATFORM_MAC)
|
||||
|
||||
#include "SandboxAPI.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -12,28 +12,5 @@ set_target_properties(Editor PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_LIST_DIR}/gui_info.plist
|
||||
RESOURCE ${CMAKE_CURRENT_LIST_DIR}/Images.xcassets
|
||||
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME EditorAppIcon
|
||||
ENTITLEMENT_FILE_PATH ${CMAKE_CURRENT_LIST_DIR}/EditorEntitlements.plist
|
||||
)
|
||||
|
||||
# We cannot use ly_add_target here because we're already including this file from inside ly_add_target
|
||||
# So we need to setup target, dependencies and install logic manually.
|
||||
add_executable(EditorDummy Platform/Mac/main_dummy.cpp)
|
||||
add_executable(AZ::EditorDummy ALIAS EditorDummy)
|
||||
|
||||
ly_target_link_libraries(EditorDummy
|
||||
PRIVATE
|
||||
AZ::AzCore
|
||||
AZ::AzFramework)
|
||||
|
||||
ly_add_dependencies(Editor EditorDummy)
|
||||
|
||||
# Store the aliased target into a DIRECTORY property
|
||||
set_property(DIRECTORY APPEND PROPERTY LY_DIRECTORY_TARGETS AZ::EditorDummy)
|
||||
|
||||
# Store the directory path in a GLOBAL property so that it can be accessed
|
||||
# in the layout install logic. Skip if the directory has already been added
|
||||
get_property(ly_all_target_directories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
|
||||
if(NOT CMAKE_CURRENT_SOURCE_DIR IN_LIST ly_all_target_directories)
|
||||
set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGET_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
ly_install_add_install_path_setreg(Editor)
|
||||
@@ -3,7 +3,7 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>EditorDummy</string>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.O3DE.Editor</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -1,75 +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/Component/ComponentApplication.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry
|
||||
AZ::ComponentApplication::Descriptor desc;
|
||||
AZ::ComponentApplication application;
|
||||
application.Create(desc);
|
||||
|
||||
AZStd::vector<AZStd::string> envVars;
|
||||
|
||||
const char* homePath = std::getenv("HOME");
|
||||
envVars.push_back(AZStd::string::format("HOME=%s", homePath));
|
||||
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
const char* dyldLibPathOrig = std::getenv("DYLD_LIBRARY_PATH");
|
||||
AZStd::string dyldSearchPath = AZStd::string::format("DYLD_LIBRARY_PATH=%s", dyldLibPathOrig);
|
||||
if (AZ::IO::FixedMaxPath projectModulePath;
|
||||
settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
|
||||
{
|
||||
dyldSearchPath.append(":");
|
||||
dyldSearchPath.append(projectModulePath.c_str());
|
||||
}
|
||||
|
||||
if (AZ::IO::FixedMaxPath installedBinariesFolder;
|
||||
settingsRegistry->Get(installedBinariesFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
|
||||
{
|
||||
if (AZ::IO::FixedMaxPath engineRootFolder;
|
||||
settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
|
||||
{
|
||||
installedBinariesFolder = engineRootFolder / installedBinariesFolder;
|
||||
dyldSearchPath.append(":");
|
||||
dyldSearchPath.append(installedBinariesFolder.c_str());
|
||||
}
|
||||
}
|
||||
envVars.push_back(dyldSearchPath);
|
||||
}
|
||||
|
||||
AZStd::string commandArgs;
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
commandArgs.append(argv[i]);
|
||||
commandArgs.append(" ");
|
||||
}
|
||||
|
||||
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
|
||||
AZ::IO::Path processPath{ AZ::IO::PathView(AZ::Utils::GetExecutableDirectory()) };
|
||||
processPath /= "Editor";
|
||||
processLaunchInfo.m_processExecutableString = AZStd::move(processPath.Native());
|
||||
processLaunchInfo.m_commandlineParameters = commandArgs;
|
||||
processLaunchInfo.m_environmentVariables = &envVars;
|
||||
processLaunchInfo.m_showWindow = true;
|
||||
|
||||
AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
|
||||
|
||||
application.Destroy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -51,4 +51,5 @@ ly_add_target(
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
AZ::AzQtComponents
|
||||
Legacy::EditorCore
|
||||
)
|
||||
|
||||
@@ -59,6 +59,20 @@ namespace AZStd
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
// interface for externally defined profiler systems
|
||||
class Profiler
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(Profiler, "{3E5D6329-72D1-41BA-9158-68A349D1A4D5}");
|
||||
|
||||
Profiler() = default;
|
||||
virtual ~Profiler() = default;
|
||||
|
||||
// support for the extra macro args (e.g. format strings) will come in a later PR
|
||||
virtual void BeginRegion(const Budget* budget, const char* eventName) = 0;
|
||||
virtual void EndRegion(const Budget* budget) = 0;
|
||||
};
|
||||
|
||||
class ProfileScope
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
template<typename... T>
|
||||
@@ -22,9 +24,11 @@ namespace AZ::Debug
|
||||
PIXBeginEvent(PIX_COLOR_INDEX(budget->Crc() & 0xff), eventName, args...);
|
||||
#endif
|
||||
budget->BeginProfileRegion();
|
||||
// TODO: injecting instrumentation for other profilers
|
||||
// NOTE: external profiler registration won't occur inline in a header necessarily in this manner, but the exact mechanism
|
||||
// will be introduced in a future PR
|
||||
|
||||
if (auto profiler = AZ::Interface<Profiler>::Get(); profiler)
|
||||
{
|
||||
profiler->BeginRegion(budget, eventName);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -39,6 +43,10 @@ namespace AZ::Debug
|
||||
#if defined(USE_PIX)
|
||||
PIXEndEvent();
|
||||
#endif
|
||||
if (auto profiler = AZ::Interface<Profiler>::Get(); profiler)
|
||||
{
|
||||
profiler->EndRegion(budget);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+18
@@ -72,6 +72,7 @@ namespace AZ
|
||||
{
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
bool fileFound = false;
|
||||
if (AZ::IO::FixedMaxPath projectModulePath;
|
||||
settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
|
||||
{
|
||||
@@ -79,6 +80,23 @@ namespace AZ
|
||||
if (AZ::IO::SystemFile::Exists(projectModulePath.c_str()))
|
||||
{
|
||||
m_fileName.assign(projectModulePath.c_str(), projectModulePath.Native().size());
|
||||
fileFound = true;
|
||||
}
|
||||
}
|
||||
if (!fileFound)
|
||||
{
|
||||
if (AZ::IO::FixedMaxPath installedBinariesPath;
|
||||
settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
|
||||
{
|
||||
if (AZ::IO::FixedMaxPath engineRootFolder;
|
||||
settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
|
||||
{
|
||||
installedBinariesPath = engineRootFolder / installedBinariesPath / fullFilePath;
|
||||
if (AZ::IO::SystemFile::Exists(installedBinariesPath.c_str()))
|
||||
{
|
||||
m_fileName.assign(installedBinariesPath.c_str(), installedBinariesPath.Native().size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <pwd.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -39,6 +40,14 @@ namespace AZ
|
||||
AZ::IO::FixedMaxPath path{homePath};
|
||||
return path.Native();
|
||||
}
|
||||
|
||||
struct passwd* pass = getpwuid(getuid());
|
||||
if (pass)
|
||||
{
|
||||
AZ::IO::FixedMaxPath path{pass->pw_dir};
|
||||
return path.Native();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace AZ::IO::ArchiveInternal
|
||||
return 0;
|
||||
}
|
||||
|
||||
nTotal = (AZStd::min)(nTotal, GetFileSize() - m_nCurSeek);
|
||||
nTotal = AZStd::min<size_t>(nTotal, GetFileSize() - m_nCurSeek);
|
||||
|
||||
int64_t nReadBytes = GetFile()->ReadData(pDest, m_nCurSeek, nTotal);
|
||||
if (nReadBytes == -1)
|
||||
|
||||
@@ -9,8 +9,19 @@
|
||||
#include <AzFramework/Viewport/ClickDetector.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
|
||||
#include <AzCore/std/chrono/clocks.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
ClickDetector::ClickDetector()
|
||||
{
|
||||
m_timeNowFn = []
|
||||
{
|
||||
const auto now = AZStd::chrono::high_resolution_clock::now();
|
||||
return AZStd::chrono::time_point_cast<AZStd::chrono::milliseconds>(now).time_since_epoch();
|
||||
};
|
||||
}
|
||||
|
||||
ClickDetector::ClickOutcome ClickDetector::DetectClick(const ClickEvent clickEvent, const ScreenVector& cursorDelta)
|
||||
{
|
||||
const auto previousDetectionState = m_detectionState;
|
||||
@@ -26,11 +37,13 @@ namespace AzFramework
|
||||
|
||||
if (clickEvent == ClickEvent::Down)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto now = m_timeNowFn();
|
||||
if (m_tryBeginTime)
|
||||
{
|
||||
const std::chrono::duration<float> diff = now - m_tryBeginTime.value();
|
||||
if (diff.count() < m_doubleClickInterval)
|
||||
using FloatingPointSeconds = AZStd::chrono::duration<float, AZStd::chrono::seconds::period>;
|
||||
|
||||
const auto diff = now - m_tryBeginTime.value();
|
||||
if (FloatingPointSeconds(diff).count() < m_doubleClickInterval)
|
||||
{
|
||||
return ClickOutcome::Nil;
|
||||
}
|
||||
@@ -43,7 +56,8 @@ namespace AzFramework
|
||||
}
|
||||
else if (clickEvent == ClickEvent::Up)
|
||||
{
|
||||
const auto clickOutcome = [detectionState = m_detectionState] {
|
||||
const auto clickOutcome = [detectionState = m_detectionState]
|
||||
{
|
||||
if (detectionState == DetectionState::WaitingForMove)
|
||||
{
|
||||
return ClickOutcome::Click;
|
||||
@@ -66,4 +80,9 @@ namespace AzFramework
|
||||
|
||||
return ClickOutcome::Nil;
|
||||
}
|
||||
|
||||
void ClickDetector::OverrideTimeNowFn(AZStd::function<AZStd::chrono::milliseconds()> timeNowFn)
|
||||
{
|
||||
m_timeNowFn = AZStd::move(timeNowFn);
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
#include <chrono>
|
||||
@@ -21,10 +22,9 @@ namespace AzFramework
|
||||
//! (mouse down with movement and then mouse up).
|
||||
class ClickDetector
|
||||
{
|
||||
//! Alias for recording time of mouse down events
|
||||
using Time = std::chrono::time_point<std::chrono::steady_clock>;
|
||||
|
||||
public:
|
||||
ClickDetector();
|
||||
|
||||
//! Internal representation of click event (map from external event for this when
|
||||
//! calling DetectClick).
|
||||
enum class ClickEvent
|
||||
@@ -51,6 +51,10 @@ namespace AzFramework
|
||||
void SetDoubleClickInterval(float doubleClickInterval);
|
||||
//! Override the dead zone before a 'move' outcome will be triggered.
|
||||
void SetDeadZone(float deadZone);
|
||||
//! Override how the current time is retrieved.
|
||||
//! This is helpful to override when it comes to simulating different passages of
|
||||
//! time to avoid double click issues in tests for example.
|
||||
void OverrideTimeNowFn(AZStd::function<AZStd::chrono::milliseconds()> timeNowFn);
|
||||
|
||||
private:
|
||||
//! Internal state of ClickDetector based on incoming events.
|
||||
@@ -65,7 +69,9 @@ namespace AzFramework
|
||||
float m_deadZone = 2.0f; //!< How far to move before a click is cancelled (when Move will fire).
|
||||
float m_doubleClickInterval = 0.4f; //!< Default double click interval, can be overridden.
|
||||
DetectionState m_detectionState; //!< Internal state of ClickDetector.
|
||||
AZStd::optional<Time> m_tryBeginTime; //!< Mouse down time (happens each mouse down, helps with double click handling).
|
||||
//! Mouse down time (happens each mouse down, helps with double click handling).
|
||||
AZStd::optional<AZStd::chrono::milliseconds> m_tryBeginTime;
|
||||
AZStd::function<AZStd::chrono::milliseconds()> m_timeNowFn; //!< Interface to query the current time.
|
||||
};
|
||||
|
||||
inline void ClickDetector::SetDoubleClickInterval(const float doubleClickInterval)
|
||||
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* 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
|
||||
+9
-1
@@ -62,8 +62,16 @@ namespace AzFramework
|
||||
|
||||
uint32_t eventMask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
||||
|
||||
const uint32_t interestedEvents =
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY
|
||||
| XCB_EVENT_MASK_BUTTON_PRESS
|
||||
| XCB_EVENT_MASK_BUTTON_RELEASE
|
||||
| XCB_EVENT_MASK_KEY_PRESS
|
||||
| XCB_EVENT_MASK_KEY_RELEASE
|
||||
| XCB_EVENT_MASK_POINTER_MOTION
|
||||
;
|
||||
uint32_t valueList[] = { xcbRootScreen->black_pixel,
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY };
|
||||
interestedEvents };
|
||||
|
||||
xcb_void_cookie_t xcbCheckResult;
|
||||
|
||||
|
||||
@@ -11,10 +11,16 @@
|
||||
if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
|
||||
|
||||
find_library(XCB_LIBRARY xcb)
|
||||
find_library(XCB_XKB_LIBRARY xcb-xkb)
|
||||
find_library(XKBCOMMON_LIBRARY xkbcommon)
|
||||
find_library(XKBCOMMON_X11_LIBRARY xkbcommon-x11)
|
||||
|
||||
set(LY_BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
${XCB_LIBRARY}
|
||||
${XKBCOMMON_LIBRARY}
|
||||
${XKBCOMMON_X11_LIBRARY}
|
||||
${XCB_XKB_LIBRARY}
|
||||
)
|
||||
|
||||
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
|
||||
|
||||
@@ -25,7 +25,7 @@ set(FILES
|
||||
AzFramework/Windowing/NativeWindow_Linux_xcb.h
|
||||
AzFramework/Windowing/NativeWindow_Linux_xcb.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad_Unimplemented.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Unimplemented.cpp
|
||||
AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.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
|
||||
|
||||
+16
@@ -18,6 +18,7 @@ namespace AzManipulatorTestFramework
|
||||
class ImmediateModeActionDispatcher
|
||||
: public ActionDispatcher<ImmediateModeActionDispatcher>
|
||||
, public AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler
|
||||
, public AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler
|
||||
{
|
||||
using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier;
|
||||
using KeyboardModifiers = AzToolsFramework::ViewportInteraction::KeyboardModifiers;
|
||||
@@ -50,6 +51,9 @@ namespace AzManipulatorTestFramework
|
||||
// EditorModifierKeyRequestBus overrides ...
|
||||
KeyboardModifiers QueryKeyboardModifiers() override;
|
||||
|
||||
// EditorViewportInputTimeNowRequestBus overrides ...
|
||||
AZStd::chrono::milliseconds EditorViewportInputTimeNow() override;
|
||||
|
||||
protected:
|
||||
// ActionDispatcher ...
|
||||
void SetSnapToGridImpl(bool enabled) override;
|
||||
@@ -79,6 +83,9 @@ namespace AzManipulatorTestFramework
|
||||
|
||||
mutable AZStd::unique_ptr<MouseInteractionEvent> m_event;
|
||||
ManipulatorViewportInteraction& m_viewportManipulatorInteraction;
|
||||
|
||||
//! Current time that ticks up after each call to EditorViewportInputTimeNow.
|
||||
AZStd::chrono::milliseconds m_timeNow = AZStd::chrono::milliseconds(0);
|
||||
};
|
||||
|
||||
template<typename ActualT, typename ExpectedT>
|
||||
@@ -106,4 +113,13 @@ namespace AzManipulatorTestFramework
|
||||
{
|
||||
return GetMouseInteractionEvent()->m_mouseInteraction.m_keyboardModifiers;
|
||||
}
|
||||
|
||||
inline AZStd::chrono::milliseconds ImmediateModeActionDispatcher::EditorViewportInputTimeNow()
|
||||
{
|
||||
// step the time for each call to be greater than the minimum time required for a double click to register
|
||||
// note: the time increment is very high to ensure any potential system changes to settings such as double
|
||||
// click interval will not be impacted
|
||||
m_timeNow += AZStd::chrono::milliseconds(10000);
|
||||
return m_timeNow;
|
||||
}
|
||||
} // namespace AzManipulatorTestFramework
|
||||
|
||||
@@ -33,10 +33,12 @@ namespace AzManipulatorTestFramework
|
||||
: m_viewportManipulatorInteraction(viewportManipulatorInteraction)
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusConnect();
|
||||
AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
ImmediateModeActionDispatcher::~ImmediateModeActionDispatcher()
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! The AZ::Interface of the central editor mode tracker for all viewports.
|
||||
class ViewportEditorModeTrackerInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(ViewportEditorModeTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}");
|
||||
|
||||
virtual ~ViewportEditorModeTrackerInterface() = default;
|
||||
|
||||
//! Activates the specified editor mode for the specified viewport.
|
||||
virtual AZ::Outcome<void, AZStd::string> ActivateMode(
|
||||
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0;
|
||||
|
||||
//! Deactivates the specified editor mode for the specified viewport.
|
||||
virtual AZ::Outcome<void, AZStd::string> DeactivateMode(
|
||||
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0;
|
||||
|
||||
//! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr.
|
||||
virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0;
|
||||
|
||||
//! Returns the number of viewports currently being tracked.
|
||||
virtual size_t GetTrackedViewportCount() const = 0;
|
||||
|
||||
//! Returns true if the specified viewport is being tracked, otherwise false.
|
||||
virtual bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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/Event.h>
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
#include <AzToolsFramework/ViewportUi/ViewportUiRequestBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! Enumeration of each viewport editor mode.
|
||||
enum class ViewportEditorMode : AZ::u8
|
||||
{
|
||||
Default,
|
||||
Component,
|
||||
Focus,
|
||||
Pick
|
||||
};
|
||||
|
||||
//! Viewport identifier and other relevant viewport data.
|
||||
struct ViewportEditorModeInfo
|
||||
{
|
||||
using IdType = AzFramework::ViewportId;
|
||||
IdType m_id = ViewportUi::DefaultViewportId; //!< The unique identifier for a given viewport.
|
||||
};
|
||||
|
||||
//! Interface for the editor modes of a given viewport.
|
||||
class ViewportEditorModesInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ViewportEditorModesInterface() = default;
|
||||
|
||||
//! Returns true if the specified editor mode is active, otherwise false.
|
||||
virtual bool IsModeActive(ViewportEditorMode mode) const = 0;
|
||||
};
|
||||
|
||||
//! Provides a bus to notify when the different editor modes are entered/exit.
|
||||
class ViewportEditorModeNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
using BusIdType = ViewportEditorModeInfo::IdType;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Notifies subscribers of the a given viewport to the activation of the specified editor mode.
|
||||
virtual void OnEditorModeActivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode)
|
||||
{
|
||||
}
|
||||
|
||||
//! Notifies subscribers of the a given viewport to the deactivation of the specified editor mode.
|
||||
virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode)
|
||||
{
|
||||
}
|
||||
};
|
||||
using ViewportEditorModeNotificationsBus = AZ::EBus<ViewportEditorModeNotifications>;
|
||||
} // namespace AzToolsFramework
|
||||
+10
-10
@@ -28,16 +28,16 @@ namespace AzToolsFramework
|
||||
namespace AssetBrowser
|
||||
{
|
||||
AssetBrowserTableView::AssetBrowserTableView(QWidget* parent)
|
||||
: QTableView(parent)
|
||||
: AzQtComponents::TableView(parent)
|
||||
, m_delegate(new EntryDelegate(this))
|
||||
{
|
||||
setSortingEnabled(true);
|
||||
setItemDelegate(m_delegate);
|
||||
verticalHeader()->hide();
|
||||
setRootIsDecorated(false);
|
||||
|
||||
//Styling the header aligning text to the left and using a bold font.
|
||||
horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
|
||||
horizontalHeader()->setStyleSheet("QHeaderView { font-weight: bold; }");
|
||||
header()->setDefaultAlignment(Qt::AlignLeft);
|
||||
header()->setStyleSheet("QHeaderView { font-weight: bold; }");
|
||||
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace AzToolsFramework
|
||||
setSortingEnabled(false);
|
||||
setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
connect(this, &QTableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu);
|
||||
connect(this, &AzQtComponents::TableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu);
|
||||
|
||||
AssetBrowserViewRequestBus::Handler::BusConnect();
|
||||
AssetBrowserComponentNotificationBus::Handler::BusConnect();
|
||||
@@ -62,11 +62,11 @@ namespace AzToolsFramework
|
||||
m_tableModel = qobject_cast<AssetBrowserTableModel*>(model);
|
||||
AZ_Assert(m_tableModel, "Expecting AssetBrowserTableModel");
|
||||
m_sourceFilterModel = qobject_cast<AssetBrowserFilterModel*>(m_tableModel->sourceModel());
|
||||
QTableView::setModel(model);
|
||||
AzQtComponents::TableView::setModel(model);
|
||||
connect(m_tableModel, &AssetBrowserTableModel::layoutChanged, this, &AssetBrowserTableView::layoutChangedSlot);
|
||||
|
||||
horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
|
||||
horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
|
||||
header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
|
||||
header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::SetName(const QString& name)
|
||||
@@ -98,7 +98,7 @@ namespace AzToolsFramework
|
||||
|
||||
void AssetBrowserTableView::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
QTableView::selectionChanged(selected, deselected);
|
||||
AzQtComponents::TableView::selectionChanged(selected, deselected);
|
||||
Q_EMIT selectionChangedSignal(selected, deselected);
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace AzToolsFramework
|
||||
selectionModel()->clear();
|
||||
}
|
||||
}
|
||||
QTableView::rowsAboutToBeRemoved(parent, start, end);
|
||||
AzQtComponents::TableView::rowsAboutToBeRemoved(parent, start, end);
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::layoutChangedSlot(
|
||||
|
||||
+3
-2
@@ -13,9 +13,10 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h>
|
||||
|
||||
#include <AzQtComponents/Components/Widgets/TableView.h>
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QPointer>
|
||||
#include <QTableView>
|
||||
#endif
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -28,7 +29,7 @@ namespace AzToolsFramework
|
||||
class EntryDelegate;
|
||||
|
||||
class AssetBrowserTableView //! Table view that displays the asset browser entries in a list.
|
||||
: public QTableView
|
||||
: public AzQtComponents::TableView
|
||||
, public AssetBrowserViewRequestBus::Handler
|
||||
, public AssetBrowserComponentNotificationBus::Handler
|
||||
{
|
||||
|
||||
@@ -282,6 +282,24 @@ namespace AzToolsFramework
|
||||
return keyboardModifiers;
|
||||
}
|
||||
|
||||
//! An interface to deal with time requests relating to viewports.
|
||||
//! @note The bus is global and not per viewport.
|
||||
class EditorViewportInputTimeNowRequests : public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
//! Returns the current time in seconds.
|
||||
//! This interface can be overridden for the purposes of testing to simplify viewport input requests.
|
||||
virtual AZStd::chrono::milliseconds EditorViewportInputTimeNow() = 0;
|
||||
|
||||
protected:
|
||||
~EditorViewportInputTimeNowRequests() = default;
|
||||
};
|
||||
|
||||
using EditorViewportInputTimeNowRequestBus = AZ::EBus<EditorViewportInputTimeNowRequests>;
|
||||
|
||||
//! Viewport requests for managing the viewport cursor state.
|
||||
class ViewportMouseCursorRequests
|
||||
{
|
||||
|
||||
+15
-4
@@ -253,10 +253,10 @@ namespace AzToolsFramework
|
||||
mouseInteraction.m_mouseInteraction.m_keyboardModifiers.Ctrl());
|
||||
}
|
||||
|
||||
static bool ManipulatorDitto(const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
|
||||
static bool ManipulatorDitto(
|
||||
const AzFramework::ClickDetector::ClickOutcome clickOutcome, const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
|
||||
{
|
||||
return mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down &&
|
||||
mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
|
||||
return clickOutcome == AzFramework::ClickDetector::ClickOutcome::Click &&
|
||||
mouseInteraction.m_mouseInteraction.m_keyboardModifiers.Ctrl() &&
|
||||
mouseInteraction.m_mouseInteraction.m_keyboardModifiers.Alt();
|
||||
}
|
||||
@@ -1054,6 +1054,17 @@ namespace AzToolsFramework
|
||||
RegisterActions();
|
||||
SetupBoxSelect();
|
||||
RefreshSelectedEntityIdsAndRegenerateManipulators();
|
||||
|
||||
// ensure the click detector uses the EditorViewportInputTimeNowRequests interface to retrieve elapsed time
|
||||
// note: this is to facilitate overriding this functionality for purposes such as testing
|
||||
m_clickDetector.OverrideTimeNowFn(
|
||||
[]
|
||||
{
|
||||
AZStd::chrono::milliseconds timeNow;
|
||||
AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::BroadcastResult(
|
||||
timeNow, &AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Events::EditorViewportInputTimeNow);
|
||||
return timeNow;
|
||||
});
|
||||
}
|
||||
|
||||
EditorTransformComponentSelection::~EditorTransformComponentSelection()
|
||||
@@ -1883,7 +1894,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
// set manipulator pivot override translation or orientation (update manipulators)
|
||||
if (Input::ManipulatorDitto(mouseInteraction))
|
||||
if (Input::ManipulatorDitto(clickOutcome, mouseInteraction))
|
||||
{
|
||||
PerformManipulatorDitto(entityIdUnderCursor);
|
||||
return false;
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
|
||||
#include <AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
AZ::Outcome<void, AZStd::string> ViewportEditorModes::ActivateMode(ViewportEditorMode mode)
|
||||
{
|
||||
if (const AZ::u32 modeIndex = static_cast<AZ::u32>(mode);
|
||||
modeIndex < NumEditorModes)
|
||||
{
|
||||
m_editorModes[modeIndex] = true;
|
||||
return AZ::Success();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZ::Failure(
|
||||
AZStd::string::format("Cannot activate mode %u, mode is not recognized", modeIndex));
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> ViewportEditorModes::DeactivateMode(ViewportEditorMode mode)
|
||||
{
|
||||
if (const AZ::u32 modeIndex = static_cast<AZ::u32>(mode); modeIndex < NumEditorModes)
|
||||
{
|
||||
m_editorModes[modeIndex] = false;
|
||||
return AZ::Success();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZ::Failure(
|
||||
AZStd::string::format("Cannot deactivate mode %u, mode is not recognized", modeIndex));
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewportEditorModes::IsModeActive(ViewportEditorMode mode) const
|
||||
{
|
||||
return m_editorModes[static_cast<AZ::u32>(mode)];
|
||||
}
|
||||
|
||||
void ViewportEditorModeTracker::RegisterInterface()
|
||||
{
|
||||
if (AZ::Interface<ViewportEditorModeTrackerInterface>::Get() == nullptr)
|
||||
{
|
||||
AZ::Interface<ViewportEditorModeTrackerInterface>::Register(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportEditorModeTracker::UnregisterInterface()
|
||||
{
|
||||
if (AZ::Interface<ViewportEditorModeTrackerInterface>::Get() != nullptr)
|
||||
{
|
||||
AZ::Interface<ViewportEditorModeTrackerInterface>::Unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> ViewportEditorModeTracker::ActivateMode(
|
||||
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode)
|
||||
{
|
||||
auto& editorModes = m_viewportEditorModesMap[viewportEditorModeInfo.m_id];
|
||||
if (editorModes.IsModeActive(mode))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Duplicate call to ActivateMode for mode '%u' on id '%i'", static_cast<AZ::u32>(mode), viewportEditorModeInfo.m_id));
|
||||
}
|
||||
|
||||
if (const auto result = editorModes.ActivateMode(mode);
|
||||
!result.IsSuccess())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
ViewportEditorModeNotificationsBus::Event(
|
||||
viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeActivated, editorModes, mode);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> ViewportEditorModeTracker::DeactivateMode(
|
||||
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode)
|
||||
{
|
||||
ViewportEditorModes* editorModes = nullptr;
|
||||
bool modeWasActive = true;
|
||||
if (m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id))
|
||||
{
|
||||
editorModes = &m_viewportEditorModesMap.at(viewportEditorModeInfo.m_id);
|
||||
if (!editorModes->IsModeActive(mode))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Duplicate call to DeactivateMode for mode '%u' on id '%i'", static_cast<AZ::u32>(mode), viewportEditorModeInfo.m_id));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
modeWasActive = false;
|
||||
editorModes = &m_viewportEditorModesMap[viewportEditorModeInfo.m_id];
|
||||
}
|
||||
|
||||
if(const auto result = editorModes->DeactivateMode(mode);
|
||||
!result.IsSuccess())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
ViewportEditorModeNotificationsBus::Event(
|
||||
viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeDeactivated, *editorModes, mode);
|
||||
|
||||
if (modeWasActive)
|
||||
{
|
||||
return AZ::Success();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Call to DeactivateMode for mode '%u' on id '%i' without precursor call to ActivateMode", static_cast<AZ::u32>(mode),
|
||||
viewportEditorModeInfo.m_id));
|
||||
}
|
||||
}
|
||||
|
||||
const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const
|
||||
{
|
||||
if (auto editorModes = m_viewportEditorModesMap.find(viewportEditorModeInfo.m_id);
|
||||
editorModes != m_viewportEditorModesMap.end())
|
||||
{
|
||||
return &editorModes->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ViewportEditorModeTracker::GetTrackedViewportCount() const
|
||||
{
|
||||
return m_viewportEditorModesMap.size();
|
||||
}
|
||||
|
||||
bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const
|
||||
{
|
||||
return m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id) > 0;
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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/RTTI/RTTI.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerInterface.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! The encapsulation of the editor modes for a given viewport.
|
||||
class ViewportEditorModes
|
||||
: public ViewportEditorModesInterface
|
||||
{
|
||||
public:
|
||||
//! The number of currently supported viewport editor modes.
|
||||
static constexpr AZ::u8 NumEditorModes = 4;
|
||||
|
||||
//! Sets the specified mode as active.
|
||||
AZ::Outcome<void, AZStd::string> ActivateMode(ViewportEditorMode mode);
|
||||
|
||||
// Sets the specified mode as inactive.
|
||||
AZ::Outcome<void, AZStd::string> DeactivateMode(ViewportEditorMode mode);
|
||||
|
||||
// ViewportEditorModesInterface ...
|
||||
bool IsModeActive(ViewportEditorMode mode) const override;
|
||||
private:
|
||||
AZStd::array<bool, NumEditorModes> m_editorModes{}; //!< State flags to track active/inactive status of viewport editor modes.
|
||||
};
|
||||
|
||||
//! The implementation of the central editor mode state tracker for all viewports.
|
||||
class ViewportEditorModeTracker
|
||||
: public ViewportEditorModeTrackerInterface
|
||||
{
|
||||
public:
|
||||
//! Registers this object with the AZ::Interface.
|
||||
void RegisterInterface();
|
||||
|
||||
//! Unregisters this object with the AZ::Interface.
|
||||
void UnregisterInterface();
|
||||
|
||||
// ViewportEditorModeTrackerInterface overrides ...
|
||||
AZ::Outcome<void, AZStd::string> ActivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override;
|
||||
AZ::Outcome<void, AZStd::string> DeactivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override;
|
||||
const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const override;
|
||||
size_t GetTrackedViewportCount() const override;
|
||||
bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override;
|
||||
|
||||
private:
|
||||
using ViewportEditorModesMap = AZStd::unordered_map<typename ViewportEditorModeInfo::IdType, ViewportEditorModes>;
|
||||
ViewportEditorModesMap m_viewportEditorModesMap; //!< Editor mode state per viewport.
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
@@ -34,6 +34,7 @@ set(FILES
|
||||
API/EditorAnimationSystemRequestBus.h
|
||||
API/EditorEntityAPI.h
|
||||
API/EditorLevelNotificationBus.h
|
||||
API/ViewportEditorModeTrackerNotificationBus.h
|
||||
API/EditorVegetationRequestsBus.h
|
||||
API/EditorPythonConsoleBus.h
|
||||
API/EditorPythonRunnerRequestsBus.h
|
||||
@@ -44,6 +45,7 @@ set(FILES
|
||||
API/EntityCompositionNotificationBus.h
|
||||
API/EditorViewportIconDisplayInterface.h
|
||||
API/ViewPaneOptions.h
|
||||
API/ViewportEditorModeTrackerInterface.h
|
||||
Application/Ticker.h
|
||||
Application/Ticker.cpp
|
||||
Application/EditorEntityManager.cpp
|
||||
@@ -538,6 +540,8 @@ set(FILES
|
||||
ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp
|
||||
ViewportSelection/EditorVisibleEntityDataCache.h
|
||||
ViewportSelection/EditorVisibleEntityDataCache.cpp
|
||||
ViewportSelection/ViewportEditorModeTracker.cpp
|
||||
ViewportSelection/ViewportEditorModeTracker.h
|
||||
ToolsFileUtils/ToolsFileUtils.h
|
||||
AssetBrowser/AssetBrowserBus.h
|
||||
AssetBrowser/AssetBrowserSourceDropBus.h
|
||||
|
||||
@@ -783,7 +783,8 @@ namespace UnitTest
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(true)->CameraState(m_cameraState)
|
||||
m_actionDispatcher->SetStickySelect(true)
|
||||
->CameraState(m_cameraState)
|
||||
->MousePosition(entity2ScreenPosition)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
|
||||
->MouseLButtonDown()
|
||||
@@ -1018,6 +1019,105 @@ namespace UnitTest
|
||||
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1));
|
||||
}
|
||||
|
||||
class EditorTransformComponentSelectionViewportPickingManipulatorTestFixtureParam
|
||||
: public EditorTransformComponentSelectionViewportPickingManipulatorTestFixture
|
||||
, public ::testing::WithParamInterface<bool>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(
|
||||
EditorTransformComponentSelectionViewportPickingManipulatorTestFixtureParam,
|
||||
StickyAndUnstickyDittoManipulatorToOtherEntityChangesManipulatorAndDoesNotChangeSelection)
|
||||
{
|
||||
PositionEntities();
|
||||
PositionCamera(m_cameraState);
|
||||
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// single click select entity2
|
||||
m_actionDispatcher->SetStickySelect(GetParam())
|
||||
->CameraState(m_cameraState)
|
||||
->MousePosition(entity2ScreenPosition)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Alt)
|
||||
->MouseLButtonDown()
|
||||
->MouseLButtonUp();
|
||||
|
||||
// entity1 is still selected
|
||||
using ::testing::UnorderedElementsAre;
|
||||
auto selectedEntitiesAfter = SelectedEntities();
|
||||
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1));
|
||||
|
||||
AZStd::optional<AZ::Transform> manipulatorTransform;
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
manipulatorTransform, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
|
||||
|
||||
EXPECT_THAT(manipulatorTransform->GetTranslation(), IsClose(m_entity2WorldTranslation));
|
||||
}
|
||||
|
||||
TEST_P(
|
||||
EditorTransformComponentSelectionViewportPickingManipulatorTestFixtureParam,
|
||||
StickyAndUnstickyDittoManipulatorToOtherEntityChangesManipulatorAndClickOffResetsManipulator)
|
||||
{
|
||||
PositionEntities();
|
||||
PositionCamera(m_cameraState);
|
||||
|
||||
AzToolsFramework::SelectEntity(m_entityId1);
|
||||
|
||||
// calculate the position in screen space of the second entity
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
|
||||
|
||||
// position in space above the entities
|
||||
const auto clickOffPositionWorld = AZ::Vector3(5.0f, 15.0f, 12.0f);
|
||||
// calculate the screen space position of the click
|
||||
const auto clickOffPositionScreen = AzFramework::WorldToScreen(clickOffPositionWorld, m_cameraState);
|
||||
|
||||
using ::testing::UnorderedElementsAre;
|
||||
// single click select entity2, then click off
|
||||
m_actionDispatcher->SetStickySelect(GetParam())
|
||||
->CameraState(m_cameraState)
|
||||
->MousePosition(entity2ScreenPosition)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Alt)
|
||||
->MouseLButtonDown()
|
||||
->MouseLButtonUp()
|
||||
->ExecuteBlock(
|
||||
[this]()
|
||||
{
|
||||
auto selectedEntitiesAfter = SelectedEntities();
|
||||
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1));
|
||||
|
||||
AZStd::optional<AZ::Transform> manipulatorTransform;
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
manipulatorTransform, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
|
||||
|
||||
EXPECT_THAT(manipulatorTransform->GetTranslation(), IsClose(m_entity2WorldTranslation));
|
||||
})
|
||||
->MousePosition(clickOffPositionScreen)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Alt)
|
||||
->MouseLButtonDown()
|
||||
->MouseLButtonUp();
|
||||
|
||||
auto selectedEntitiesAfter = SelectedEntities();
|
||||
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1));
|
||||
|
||||
AZStd::optional<AZ::Transform> manipulatorTransform;
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
manipulatorTransform, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
|
||||
|
||||
// manipulator transform is reset
|
||||
EXPECT_THAT(manipulatorTransform->GetTranslation(), IsClose(m_entity1WorldTranslation));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(All, EditorTransformComponentSelectionViewportPickingManipulatorTestFixtureParam, testing::Values(true, false));
|
||||
|
||||
using EditorTransformComponentSelectionManipulatorTestFixture =
|
||||
IndirectCallManipulatorViewportInteractionFixtureMixin<EditorTransformComponentSelectionFixture>;
|
||||
|
||||
|
||||
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* 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 <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
#include <AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using ViewportEditorMode = AzToolsFramework::ViewportEditorMode;
|
||||
using ViewportEditorModes = AzToolsFramework::ViewportEditorModes;
|
||||
using ViewportEditorModeTracker = AzToolsFramework::ViewportEditorModeTracker;
|
||||
using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo;
|
||||
using ViewportId = ViewportEditorModeInfo::IdType;
|
||||
using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface;
|
||||
|
||||
void ActivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode)
|
||||
{
|
||||
const auto result = editorModeState.ActivateMode(mode);
|
||||
EXPECT_TRUE(result.IsSuccess());
|
||||
}
|
||||
|
||||
void DeactivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode)
|
||||
{
|
||||
const auto result = editorModeState.DeactivateMode(mode);
|
||||
EXPECT_TRUE(result.IsSuccess());
|
||||
}
|
||||
|
||||
void SetAllModesActive(ViewportEditorModes& editorModeState)
|
||||
{
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
ActivateModeAndExpectSuccess(editorModeState, static_cast<ViewportEditorMode>(mode));
|
||||
}
|
||||
}
|
||||
|
||||
void SetAllModesInactive(ViewportEditorModes& editorModeState)
|
||||
{
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
DeactivateModeAndExpectSuccess(editorModeState, static_cast<ViewportEditorMode>(mode));
|
||||
}
|
||||
}
|
||||
|
||||
// Fixture for testing editor mode states
|
||||
class ViewportEditorModesTestsFixture
|
||||
: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
ViewportEditorModes m_editorModes;
|
||||
};
|
||||
|
||||
// Fixture for testing editor mode states with parameterized test arguments
|
||||
class ViewportEditorModesTestsFixtureWithParams
|
||||
: public ViewportEditorModesTestsFixture
|
||||
, public ::testing::WithParamInterface<AzToolsFramework::ViewportEditorMode>
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
m_selectedEditorMode = GetParam();
|
||||
}
|
||||
|
||||
ViewportEditorMode m_selectedEditorMode;
|
||||
};
|
||||
|
||||
// Fixture for testing the viewport editor mode state tracker
|
||||
class ViewportEditorModeTrackerTestFixture
|
||||
: public ToolsApplicationFixture
|
||||
{
|
||||
public:
|
||||
ViewportEditorModeTracker m_viewportEditorModeTracker;
|
||||
};
|
||||
|
||||
// Subscriber of viewport editor mode notifications for a single viewport that expects a single mode to be activated/deactivated
|
||||
class ViewportEditorModeNotificationsBusHandler
|
||||
: private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler
|
||||
{
|
||||
public:
|
||||
struct ReceivedEvents
|
||||
{
|
||||
bool m_onEnter = false;
|
||||
bool m_onExit = false;
|
||||
};
|
||||
|
||||
using EditModeTracker = AZStd::unordered_map<ViewportEditorMode, ReceivedEvents>;
|
||||
|
||||
ViewportEditorModeNotificationsBusHandler(ViewportId viewportId)
|
||||
: m_viewportSubscription(viewportId)
|
||||
{
|
||||
AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusConnect(m_viewportSubscription);
|
||||
}
|
||||
|
||||
~ViewportEditorModeNotificationsBusHandler()
|
||||
{
|
||||
AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
ViewportId GetViewportSubscription() const
|
||||
{
|
||||
return m_viewportSubscription;
|
||||
}
|
||||
|
||||
const EditModeTracker& GetEditorModes() const
|
||||
{
|
||||
return m_editorModes;
|
||||
}
|
||||
|
||||
void OnEditorModeActivated([[maybe_unused]]const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override
|
||||
{
|
||||
m_editorModes[mode].m_onEnter = true;
|
||||
}
|
||||
|
||||
virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override
|
||||
{
|
||||
m_editorModes[mode].m_onExit = true;
|
||||
}
|
||||
|
||||
private:
|
||||
ViewportId m_viewportSubscription;
|
||||
EditModeTracker m_editorModes;
|
||||
|
||||
};
|
||||
|
||||
// Fixture for testing viewport editor mode notifications publishing
|
||||
class ViewportEditorModePublisherTestFixture
|
||||
: public ViewportEditorModeTrackerTestFixture
|
||||
{
|
||||
public:
|
||||
|
||||
void SetUpEditorFixtureImpl() override
|
||||
{
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
m_editorModeHandlers[mode] = AZStd::make_unique<ViewportEditorModeNotificationsBusHandler>(mode);
|
||||
}
|
||||
}
|
||||
|
||||
void TearDownEditorFixtureImpl() override
|
||||
{
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
m_editorModeHandlers[mode].reset();
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::array<AZStd::unique_ptr<ViewportEditorModeNotificationsBusHandler>, ViewportEditorModes::NumEditorModes> m_editorModeHandlers;
|
||||
};
|
||||
|
||||
TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4)
|
||||
{
|
||||
EXPECT_EQ(ViewportEditorModes::NumEditorModes, 4);
|
||||
}
|
||||
|
||||
TEST_F(ViewportEditorModesTestsFixture, InitialEditorModeStateHasAllInactiveModes)
|
||||
{
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
EXPECT_FALSE(m_editorModes.IsModeActive(static_cast<ViewportEditorMode>(mode)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode)
|
||||
{
|
||||
ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode);
|
||||
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
const auto editorMode = static_cast<ViewportEditorMode>(mode);
|
||||
if (editorMode == m_selectedEditorMode)
|
||||
{
|
||||
EXPECT_TRUE(m_editorModes.IsModeActive(static_cast<ViewportEditorMode>(editorMode)));
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_FALSE(m_editorModes.IsModeActive(static_cast<ViewportEditorMode>(editorMode)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode)
|
||||
{
|
||||
SetAllModesActive(m_editorModes);
|
||||
DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode);
|
||||
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
const auto editorMode = static_cast<ViewportEditorMode>(mode);
|
||||
if (editorMode == m_selectedEditorMode)
|
||||
{
|
||||
EXPECT_FALSE(m_editorModes.IsModeActive(editorMode));
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_TRUE(m_editorModes.IsModeActive(editorMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively)
|
||||
{
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes - 1; mode++)
|
||||
{
|
||||
// Given only the selected mode active
|
||||
SetAllModesInactive(m_editorModes);
|
||||
{
|
||||
ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode);
|
||||
}
|
||||
|
||||
const auto editorMode = static_cast<ViewportEditorMode>(mode);
|
||||
if (editorMode == m_selectedEditorMode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// When other modes are activated
|
||||
ActivateModeAndExpectSuccess(m_editorModes, editorMode);
|
||||
|
||||
for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++)
|
||||
{
|
||||
const auto expectedEditorMode = static_cast<ViewportEditorMode>(expectedMode);
|
||||
if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode)
|
||||
{
|
||||
// Expect the activated modes to be active
|
||||
EXPECT_TRUE(m_editorModes.IsModeActive(expectedEditorMode));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expect the modes not active to be inactive
|
||||
EXPECT_FALSE(m_editorModes.IsModeActive(expectedEditorMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesInactiveInactivatesAllThoseModesNonMutuallyExclusively)
|
||||
{
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes - 1; mode++)
|
||||
{
|
||||
// Given only the selected mode inactive
|
||||
SetAllModesActive(m_editorModes);
|
||||
DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode);
|
||||
|
||||
const auto editorMode = static_cast<ViewportEditorMode>(mode);
|
||||
if (editorMode == m_selectedEditorMode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// When other modes are deactivated
|
||||
DeactivateModeAndExpectSuccess(m_editorModes, editorMode);
|
||||
|
||||
for (auto expectedMode = 0; expectedMode < ViewportEditorModes::NumEditorModes; expectedMode++)
|
||||
{
|
||||
const auto expectedEditorMode = static_cast<ViewportEditorMode>(expectedMode);
|
||||
if (expectedEditorMode == editorMode || expectedEditorMode == m_selectedEditorMode)
|
||||
{
|
||||
// Expect the deactivated modes to be inactive
|
||||
EXPECT_FALSE(m_editorModes.IsModeActive(expectedEditorMode));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expects the modes not deactivated to still be active
|
||||
EXPECT_TRUE(m_editorModes.IsModeActive(expectedEditorMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AllEditorModes,
|
||||
ViewportEditorModesTestsFixtureWithParams,
|
||||
::testing::Values(
|
||||
AzToolsFramework::ViewportEditorMode::Default,
|
||||
AzToolsFramework::ViewportEditorMode::Component,
|
||||
AzToolsFramework::ViewportEditorMode::Focus,
|
||||
AzToolsFramework::ViewportEditorMode::Pick));
|
||||
|
||||
TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeActiveReturnsError)
|
||||
{
|
||||
const auto result = m_editorModes.ActivateMode(static_cast<ViewportEditorMode>(ViewportEditorModes::NumEditorModes));
|
||||
EXPECT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(ViewportEditorModesTestsFixture, SettingOutOfBoundsModeInactiveReturnsError)
|
||||
{
|
||||
const auto result = m_editorModes.DeactivateMode(static_cast<ViewportEditorMode>(ViewportEditorModes::NumEditorModes));
|
||||
EXPECT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(ViewportEditorModeTrackerTestFixture, InitialCentralStateTrackerHasNoViewportEditorModess)
|
||||
{
|
||||
EXPECT_EQ(m_viewportEditorModeTracker.GetTrackedViewportCount(), 0);
|
||||
}
|
||||
|
||||
TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId)
|
||||
{
|
||||
// Given a viewport not currently being tracked
|
||||
const ViewportId viewportid = 0;
|
||||
EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr);
|
||||
|
||||
// When a mode is activated for that viewport
|
||||
const auto editorMode = ViewportEditorMode::Default;
|
||||
m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode);
|
||||
const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid });
|
||||
|
||||
// Expect that viewport to now be tracked
|
||||
EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
EXPECT_NE(viewportEditorModeState, nullptr);
|
||||
|
||||
// Expect the mode for that viewport to be active
|
||||
EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode));
|
||||
}
|
||||
|
||||
TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError)
|
||||
{
|
||||
// Given a viewport not currently being tracked
|
||||
const ViewportId viewportid = 0;
|
||||
EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr);
|
||||
|
||||
// When a mode is deactivated for that viewport
|
||||
const auto editorMode = ViewportEditorMode::Default;
|
||||
const auto expectedErrorMsg = AZStd::string::format(
|
||||
"Call to DeactivateMode for mode '%u' on id '%i' without precursor call to ActivateMode", static_cast<AZ::u32>(editorMode), viewportid);
|
||||
const auto result = m_viewportEditorModeTracker.DeactivateMode({ viewportid }, editorMode);
|
||||
|
||||
// Expect an error due to no precursor activation of that mode
|
||||
EXPECT_FALSE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetError(), expectedErrorMsg);
|
||||
|
||||
// Expect that viewport to now be tracked
|
||||
const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid });
|
||||
EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
|
||||
// Expect the mode for that viewport to be inactive
|
||||
EXPECT_NE(viewportEditorModeState, nullptr);
|
||||
EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode));
|
||||
}
|
||||
|
||||
TEST_F(ViewportEditorModeTrackerTestFixture, GettingNonExistentViewportEditorModesForIdReturnsNull)
|
||||
{
|
||||
const ViewportId viewportid = 0;
|
||||
EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateReturnsError)
|
||||
{
|
||||
// Given a viewport not currently tracked
|
||||
const ViewportId viewportid = 0;
|
||||
EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr);
|
||||
|
||||
const auto editorMode = ViewportEditorMode::Default;
|
||||
{
|
||||
// When the mode is activated for the viewport
|
||||
const auto result = m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode);
|
||||
|
||||
// Expect no error as there is no duplicate activation
|
||||
EXPECT_TRUE(result.IsSuccess());
|
||||
|
||||
// Expect the mode to be active for the viewport
|
||||
const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid });
|
||||
EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
EXPECT_NE(viewportEditorModeState, nullptr);
|
||||
EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode));
|
||||
}
|
||||
{
|
||||
// When the mode is activated again for the viewport
|
||||
const auto result = m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode);
|
||||
|
||||
// Expect an error for the duplicate activation
|
||||
const auto expectedErrorMsg = AZStd::string::format(
|
||||
"Duplicate call to ActivateMode for mode '%u' on id '%i'", static_cast<AZ::u32>(editorMode), viewportid);
|
||||
EXPECT_FALSE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetError(), expectedErrorMsg);
|
||||
|
||||
// Expect the mode to still be active for the viewport
|
||||
const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid });
|
||||
EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
EXPECT_NE(viewportEditorModeState, nullptr);
|
||||
EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateReturnssError)
|
||||
{
|
||||
// Given a viewport not currently tracked
|
||||
const ViewportId viewportid = 0;
|
||||
EXPECT_FALSE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr);
|
||||
|
||||
const auto editorMode = ViewportEditorMode::Default;
|
||||
{
|
||||
// When the mode is activated and then deactivated for the viewport
|
||||
m_viewportEditorModeTracker.ActivateMode({ viewportid }, editorMode);
|
||||
const auto result = m_viewportEditorModeTracker.DeactivateMode({ viewportid }, editorMode);
|
||||
|
||||
// Expect no error as there is no duplicate deactivation
|
||||
EXPECT_TRUE(result.IsSuccess());
|
||||
|
||||
// Expect the mode to be inctive for the viewport
|
||||
const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid });
|
||||
EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
EXPECT_NE(viewportEditorModeState, nullptr);
|
||||
EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode));
|
||||
}
|
||||
{
|
||||
// When the mode is deactivated again for the viewport
|
||||
const auto result = m_viewportEditorModeTracker.DeactivateMode({ viewportid }, editorMode);
|
||||
|
||||
// Expect an error for the duplicate deactivation
|
||||
const auto expectedErrorMsg = AZStd::string::format(
|
||||
"Duplicate call to DeactivateMode for mode '%u' on id '%i'", static_cast<AZ::u32>(editorMode), viewportid);
|
||||
EXPECT_FALSE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetError(), expectedErrorMsg);
|
||||
|
||||
// Expect the mode to still be inactive for the viewport
|
||||
const auto* viewportEditorModeState = m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid });
|
||||
EXPECT_TRUE(m_viewportEditorModeTracker.IsViewportModeTracked({ viewportid }));
|
||||
EXPECT_NE(viewportEditorModeState, nullptr);
|
||||
EXPECT_FALSE(viewportEditorModeState->IsModeActive(editorMode));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ViewportEditorModePublisherTestFixture,
|
||||
RegisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeRegisterEventForAllSubscribers)
|
||||
{
|
||||
// Given a set of subscribers tracking the editor modes for their exclusive viewport
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
// Expect each subscriber to have received no editor mode state changes
|
||||
EXPECT_EQ(m_editorModeHandlers[mode]->GetEditorModes().size(), 0);
|
||||
}
|
||||
|
||||
// When each editor mode is activated by the state tracker for a specific viewport
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
const ViewportId viewportId = mode;
|
||||
const ViewportEditorMode editorMode = static_cast<ViewportEditorMode>(mode);
|
||||
m_viewportEditorModeTracker.ActivateMode({ viewportId }, editorMode);
|
||||
}
|
||||
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
// Expect only the subscribers of each viewport to have received the editor mode activated event
|
||||
const ViewportEditorMode editorMode = static_cast<ViewportEditorMode>(mode);
|
||||
const auto& editorModes = m_editorModeHandlers[mode]->GetEditorModes();
|
||||
EXPECT_EQ(editorModes.size(), 1);
|
||||
EXPECT_EQ(editorModes.count(editorMode), 1);
|
||||
const auto& expectedEditorModeSet = editorModes.find(editorMode);
|
||||
EXPECT_NE(expectedEditorModeSet, editorModes.end());
|
||||
EXPECT_TRUE(expectedEditorModeSet->second.m_onEnter);
|
||||
EXPECT_FALSE(expectedEditorModeSet->second.m_onExit);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ViewportEditorModePublisherTestFixture,
|
||||
UnregisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeUnregisterEventForAllSubscribers)
|
||||
{
|
||||
// Given a set of subscribers tracking the editor modes for their exclusive viewport
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
EXPECT_EQ(m_editorModeHandlers[mode]->GetEditorModes().size(), 0);
|
||||
}
|
||||
|
||||
// When each editor mode is activated deactivated by the state tracker for a specific viewport
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
const ViewportId viewportId = mode;
|
||||
const ViewportEditorMode editorMode = static_cast<ViewportEditorMode>(mode);
|
||||
m_viewportEditorModeTracker.ActivateMode({ viewportId }, editorMode);
|
||||
m_viewportEditorModeTracker.DeactivateMode({ viewportId }, editorMode);
|
||||
}
|
||||
|
||||
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
|
||||
{
|
||||
// Expect only the subscribers of each viewport to have received the editor mode activated and deactivated event
|
||||
const ViewportEditorMode editorMode = static_cast<ViewportEditorMode>(mode);
|
||||
const auto& editorModes = m_editorModeHandlers[mode]->GetEditorModes();
|
||||
EXPECT_EQ(editorModes.size(), 1);
|
||||
EXPECT_EQ(editorModes.count(editorMode), 1);
|
||||
const auto& expectedEditorModeSet = editorModes.find(editorMode);
|
||||
EXPECT_NE(expectedEditorModeSet, editorModes.end());
|
||||
EXPECT_TRUE(expectedEditorModeSet->second.m_onEnter);
|
||||
EXPECT_TRUE(expectedEditorModeSet->second.m_onExit);
|
||||
}
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@@ -110,6 +110,7 @@ set(FILES
|
||||
UI/EntityPropertyEditorTests.cpp
|
||||
UndoStack.cpp
|
||||
Viewport/ClusterTests.cpp
|
||||
Viewport/ViewportEditorModeTests.cpp
|
||||
Viewport/ViewportScreenTests.cpp
|
||||
Viewport/ViewportUiClusterTests.cpp
|
||||
Viewport/ViewportUiDisplayTests.cpp
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -12,28 +12,5 @@ set_target_properties(AssetProcessor PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Platform/Mac/gui_info.plist
|
||||
RESOURCE ${CMAKE_CURRENT_SOURCE_DIR}/Platform/Mac/Images.xcassets
|
||||
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME AssetProcessorAppIcon
|
||||
ENTITLEMENT_FILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Platform/Mac/AssetProcessorEntitlements.plist
|
||||
)
|
||||
|
||||
# We cannot use ly_add_target here because we're already including this file from inside ly_add_target
|
||||
# So we need to setup target, dependencies and install logic manually.
|
||||
add_executable(AssetProcessorDummy Platform/Mac/main_dummy.cpp)
|
||||
add_executable(AZ::AssetProcessorDummy ALIAS AssetProcessorDummy)
|
||||
|
||||
ly_target_link_libraries(AssetProcessorDummy
|
||||
PRIVATE
|
||||
AZ::AzCore
|
||||
AZ::AzFramework)
|
||||
|
||||
ly_add_dependencies(AssetProcessor AssetProcessorDummy)
|
||||
|
||||
# Store the aliased target into a DIRECTORY property
|
||||
set_property(DIRECTORY APPEND PROPERTY LY_DIRECTORY_TARGETS AZ::AssetProcessorDummy)
|
||||
|
||||
# Store the directory path in a GLOBAL property so that it can be accessed
|
||||
# in the layout install logic. Skip if the directory has already been added
|
||||
get_property(ly_all_target_directories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
|
||||
if(NOT CMAKE_CURRENT_SOURCE_DIR IN_LIST ly_all_target_directories)
|
||||
set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGET_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
ly_install_add_install_path_setreg(AssetProcessor)
|
||||
@@ -11,7 +11,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>ASPR</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>AssetProcessorDummy</string>
|
||||
<string>AssetProcessor</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.Amazon.AssetProcessor</string>
|
||||
</dict>
|
||||
|
||||
@@ -1,75 +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/Component/ComponentApplication.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry
|
||||
AZ::ComponentApplication::Descriptor desc;
|
||||
AZ::ComponentApplication application;
|
||||
application.Create(desc);
|
||||
|
||||
AZStd::vector<AZStd::string> envVars;
|
||||
|
||||
const char* homePath = std::getenv("HOME");
|
||||
envVars.push_back(AZStd::string::format("HOME=%s", homePath));
|
||||
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
const char* dyldLibPathOrig = std::getenv("DYLD_LIBRARY_PATH");
|
||||
AZStd::string dyldSearchPath = AZStd::string::format("DYLD_LIBRARY_PATH=%s", dyldLibPathOrig);
|
||||
if (AZ::IO::FixedMaxPath projectModulePath;
|
||||
settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
|
||||
{
|
||||
dyldSearchPath.append(":");
|
||||
dyldSearchPath.append(projectModulePath.c_str());
|
||||
}
|
||||
|
||||
if (AZ::IO::FixedMaxPath installedBinariesFolder;
|
||||
settingsRegistry->Get(installedBinariesFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
|
||||
{
|
||||
if (AZ::IO::FixedMaxPath engineRootFolder;
|
||||
settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
|
||||
{
|
||||
installedBinariesFolder = engineRootFolder / installedBinariesFolder;
|
||||
dyldSearchPath.append(":");
|
||||
dyldSearchPath.append(installedBinariesFolder.c_str());
|
||||
}
|
||||
}
|
||||
envVars.push_back(dyldSearchPath);
|
||||
}
|
||||
|
||||
AZStd::string commandArgs;
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
commandArgs.append(argv[i]);
|
||||
commandArgs.append(" ");
|
||||
}
|
||||
|
||||
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
|
||||
AZ::IO::Path processPath{ AZ::IO::PathView(AZ::Utils::GetExecutableDirectory()) };
|
||||
processPath /= "AssetProcessor";
|
||||
processLaunchInfo.m_processExecutableString = AZStd::move(processPath.Native());
|
||||
processLaunchInfo.m_commandlineParameters = commandArgs;
|
||||
processLaunchInfo.m_environmentVariables = &envVars;
|
||||
processLaunchInfo.m_showWindow = true;
|
||||
|
||||
AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
|
||||
|
||||
application.Destroy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
# This is the launcher that will be used by the O3DE_SDK.app bundle
|
||||
# generated by the cmake install process for Mac.
|
||||
if(NOT ${PAL_PLATFORM_NAME} STREQUAL Mac)
|
||||
return()
|
||||
endif()
|
||||
|
||||
ly_add_target(
|
||||
NAME O3DE_SDK EXECUTABLE
|
||||
NAMESPACE AZ
|
||||
FILES_CMAKE
|
||||
O3DE_SDK_files.cmake
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzCore
|
||||
AZ::AzFramework
|
||||
)
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <mach-o/dyld.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// We need to pass in the engine path since we won't be able to find it by searching upwards.
|
||||
// We can't use any containers that use our custom allocator till after the call to ComponentApplication::Create()
|
||||
AZ::IO::FixedMaxPath processPath = AZ::Utils::GetExecutableDirectory();
|
||||
AZ::IO::FixedMaxPath enginePath = (processPath / "../Engine").LexicallyNormal();
|
||||
auto enginePathParam = AZ::SettingsRegistryInterface::FixedValueString::format(R"(--engine-path="%s")", enginePath.c_str());
|
||||
// Uses the fixed_vector deduction guide to determine the type is AZStd::fixed_vector<char*, 2>
|
||||
AZStd::fixed_vector commandLineParams{ processPath.Native().data(), enginePathParam.data() };
|
||||
|
||||
|
||||
// Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry
|
||||
AZ::ComponentApplication application(static_cast<int>(commandLineParams.size()), commandLineParams.data());
|
||||
application.Create(AZ::ComponentApplication::Descriptor());
|
||||
|
||||
AZ::IO::FixedMaxPath installedBinariesFolder;
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
if (settingsRegistry->Get(installedBinariesFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
|
||||
{
|
||||
installedBinariesFolder = enginePath / installedBinariesFolder;
|
||||
}
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPath shellPath = "/bin/sh";
|
||||
AZStd::string parameters = AZStd::string::format("-c \"export LY_CMAKE_PATH=/usr/local/bin && \"%s/python/get_python.sh\"\"", enginePath.c_str());
|
||||
AzFramework::ProcessLauncher::ProcessLaunchInfo shellProcessLaunch;
|
||||
shellProcessLaunch.m_processExecutableString = AZStd::move(shellPath.Native());
|
||||
shellProcessLaunch.m_commandlineParameters = parameters;
|
||||
shellProcessLaunch.m_showWindow = true;
|
||||
shellProcessLaunch.m_workingDirectory = enginePath.String();
|
||||
AZStd::unique_ptr<AzFramework::ProcessWatcher> shellProcess(AzFramework::ProcessWatcher::LaunchProcess(shellProcessLaunch, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE));
|
||||
shellProcess->WaitForProcessToExit(120);
|
||||
shellProcess.reset();
|
||||
|
||||
AZ::IO::FixedMaxPath projectManagerPath = installedBinariesFolder/"o3de.app"/"Contents"/"MacOS"/"o3de";
|
||||
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
|
||||
processLaunchInfo.m_processExecutableString = AZStd::move(projectManagerPath.Native());
|
||||
processLaunchInfo.m_showWindow = true;
|
||||
AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
|
||||
|
||||
application.Destroy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# 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
|
||||
O3DE_SDK_Launcher.cpp
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>O3DE_SDK</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.O3DE.O3DE_SDK</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright (c) Contributors to the Open 3D Engine Project.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -20,3 +20,4 @@ add_subdirectory(GridHub)
|
||||
add_subdirectory(Standalone)
|
||||
add_subdirectory(TestImpactFramework)
|
||||
add_subdirectory(ProjectManager)
|
||||
add_subdirectory(BundleLauncher)
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.33301 6H12.6663V14.6667H3.33301V6ZM5.33301 7.33333H6.66634V13.3333H5.33301V7.33333ZM10.6663 7.33333H9.33301V13.3333H10.6663V7.33333Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6667 2H5.33333V3.33333H2V4.66667H14V3.33333H10.6667V2Z" fill="#E9E9E9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 430 B |
@@ -0,0 +1,7 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="1.33333" height="12" fill="white"/>
|
||||
<rect x="2" y="12.6666" width="12" height="1.33333" fill="white"/>
|
||||
<rect x="5.33301" y="9.20911" width="10.6667" height="2" transform="rotate(-45 5.33301 9.20911)" fill="white"/>
|
||||
<rect x="2" y="2" width="6.66667" height="1.33333" fill="white"/>
|
||||
<rect width="1.33333" height="6.66667" transform="matrix(-1 0 0 1 14 7.33337)" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 503 B |
@@ -35,5 +35,8 @@
|
||||
<file>Backgrounds/DefaultBackground.jpg</file>
|
||||
<file>Backgrounds/FtueBackground.jpg</file>
|
||||
<file>FeatureTagClose.svg</file>
|
||||
<file>Refresh.svg</file>
|
||||
<file>Edit.svg</file>
|
||||
<file>Delete.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -518,3 +518,82 @@ QProgressBar::chunk {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/************** Engine **************/
|
||||
|
||||
#engineTab::tab-bar {
|
||||
left: 60px;
|
||||
}
|
||||
|
||||
#engineTabBar::tab {
|
||||
height: 50px;
|
||||
background-color: transparent;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
#engineTabBar::tab:selected {
|
||||
border-bottom: 3px solid #94D2FF;
|
||||
color: #94D2FF;
|
||||
font-weight: 600;
|
||||
}
|
||||
#engineTabBar::tab:hover {
|
||||
color: #94D2FF;
|
||||
font-weight: 600;
|
||||
}
|
||||
#engineTabBar::tab:pressed {
|
||||
color: #66bcfa;
|
||||
}
|
||||
|
||||
#engineTopFrame {
|
||||
background-color:#1E252F;
|
||||
}
|
||||
|
||||
/************** Gem Repo **************/
|
||||
|
||||
#gemRepoHeaderLabel {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#gemRepoHeaderRefreshButton {
|
||||
background-color: transparent;
|
||||
qproperty-flat: true;
|
||||
qproperty-iconSize: 14px;
|
||||
}
|
||||
|
||||
#gemRepoHeaderAddButton {
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
stop: 0 #888888, stop: 1.0 #555555);
|
||||
qproperty-flat: true;
|
||||
margin-right:30px;
|
||||
min-width:120px;
|
||||
max-width:120px;
|
||||
min-height:24px;
|
||||
max-height:24px;
|
||||
border-radius: 3px;
|
||||
text-align:center;
|
||||
font-size:12px;
|
||||
font-weight:600;
|
||||
}
|
||||
#gemRepoHeaderAddButton:hover {
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
stop: 0 #999999, stop: 1.0 #666666);
|
||||
}
|
||||
#gemRepoHeaderAddButton:pressed {
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
stop: 0 #555555, stop: 1.0 #777777);
|
||||
}
|
||||
|
||||
#gemRepoHeaderTable {
|
||||
background-color: transparent;
|
||||
max-height: 30px;
|
||||
}
|
||||
|
||||
#gemRepoListHeader {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#gemRepoInspector {
|
||||
background: #444444;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg width="15" height="12" viewBox="0 0 15 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.046 5.85448C13.046 5.869 13.0436 5.66561 13.0436 5.68014H14.5278L12.3341 8.22252L10.1114 5.68014H11.6481C11.6481 5.66561 11.6513 5.869 11.6513 5.85448C11.6513 3.42833 9.77724 1.46707 7.46731 1.46707C6.42131 1.46707 5.46247 1.87385 4.73608 2.54213L3.8063 1.43801C4.79419 0.537286 6.07264 -0.000244141 7.46731 -0.000244141C10.5472 -0.000244141 13.046 2.6293 13.046 5.85448Z" fill="white"/>
|
||||
<path d="M1.48184 6.14503C1.48184 6.13051 1.48428 6.3339 1.48428 6.31937H0L2.1937 3.777L4.41646 6.31937H2.87975C2.87975 6.3339 2.87651 6.13051 2.87651 6.14503C2.87651 8.57118 4.7506 10.5324 7.06053 10.5324C8.10654 10.5324 9.06537 10.1257 9.79177 9.45738L10.7215 10.5615C9.73366 11.4622 8.4552 11.9998 7.06053 11.9998C3.98063 11.9998 1.48184 9.37022 1.48184 6.14503Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 886 B |
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <EngineScreenCtrl.h>
|
||||
#include <GemRepo/GemRepoScreen.h>
|
||||
#include <EngineSettingsScreen.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QTabWidget>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
EngineScreenCtrl::EngineScreenCtrl(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
vLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
QFrame* topBarFrameWidget = new QFrame(this);
|
||||
topBarFrameWidget->setObjectName("engineTopFrame");
|
||||
QHBoxLayout* topBarHLayout = new QHBoxLayout();
|
||||
topBarHLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
topBarFrameWidget->setLayout(topBarHLayout);
|
||||
|
||||
QTabWidget* tabWidget = new QTabWidget();
|
||||
tabWidget->setObjectName("engineTab");
|
||||
tabWidget->tabBar()->setObjectName("engineTabBar");
|
||||
tabWidget->tabBar()->setFocusPolicy(Qt::TabFocus);
|
||||
|
||||
m_engineSettingsScreen = new EngineSettingsScreen();
|
||||
m_gemRepoScreen = new GemRepoScreen();
|
||||
|
||||
tabWidget->addTab(m_engineSettingsScreen, tr("General"));
|
||||
tabWidget->addTab(m_gemRepoScreen, tr("Gem Repositories"));
|
||||
topBarHLayout->addWidget(tabWidget);
|
||||
|
||||
vLayout->addWidget(topBarFrameWidget);
|
||||
|
||||
setLayout(vLayout);
|
||||
}
|
||||
|
||||
ProjectManagerScreen EngineScreenCtrl::GetScreenEnum()
|
||||
{
|
||||
return ProjectManagerScreen::UpdateProject;
|
||||
}
|
||||
|
||||
QString EngineScreenCtrl::GetTabText()
|
||||
{
|
||||
return tr("Engine");
|
||||
}
|
||||
|
||||
bool EngineScreenCtrl::IsTab()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
QT_FORWARD_DECLARE_CLASS(EngineSettingsScreen)
|
||||
QT_FORWARD_DECLARE_CLASS(GemRepoScreen)
|
||||
|
||||
class EngineScreenCtrl
|
||||
: public ScreenWidget
|
||||
{
|
||||
public:
|
||||
explicit EngineScreenCtrl(QWidget* parent = nullptr);
|
||||
~EngineScreenCtrl() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
QString GetTabText() override;
|
||||
bool IsTab() override;
|
||||
|
||||
EngineSettingsScreen* m_engineSettingsScreen = nullptr;
|
||||
GemRepoScreen* m_gemRepoScreen = nullptr;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -7,15 +7,16 @@
|
||||
*/
|
||||
|
||||
#include <EngineSettingsScreen.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <FormLineEditWidget.h>
|
||||
#include <FormFolderBrowseEditWidget.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <PathValidator.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
EngineSettingsScreen::EngineSettingsScreen(QWidget* parent)
|
||||
@@ -78,16 +79,6 @@ namespace O3DE::ProjectManager
|
||||
return ProjectManagerScreen::EngineSettings;
|
||||
}
|
||||
|
||||
QString EngineSettingsScreen::GetTabText()
|
||||
{
|
||||
return tr("Engine");
|
||||
}
|
||||
|
||||
bool EngineSettingsScreen::IsTab()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void EngineSettingsScreen::OnTextChanged()
|
||||
{
|
||||
// save engine settings
|
||||
|
||||
@@ -24,8 +24,6 @@ namespace O3DE::ProjectManager
|
||||
~EngineSettingsScreen() = default;
|
||||
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
QString GetTabText() override;
|
||||
bool IsTab() override;
|
||||
|
||||
protected slots:
|
||||
void OnTextChanged();
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <GemRepo/GemRepoInfo.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemRepoInfo::GemRepoInfo(
|
||||
const QString& name, const QString& creator, const QString& summary, const QDateTime& lastUpdated, bool isEnabled = true)
|
||||
: m_name(name)
|
||||
, m_creator(creator)
|
||||
, m_summary(summary)
|
||||
, m_lastUpdated(lastUpdated)
|
||||
, m_isEnabled(isEnabled)
|
||||
{
|
||||
}
|
||||
|
||||
bool GemRepoInfo::IsValid() const
|
||||
{
|
||||
return !m_name.isEmpty();
|
||||
}
|
||||
|
||||
bool GemRepoInfo::operator<(const GemRepoInfo& gemRepoInfo) const
|
||||
{
|
||||
return (m_lastUpdated < gemRepoInfo.m_lastUpdated);
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemRepoInfo
|
||||
{
|
||||
public:
|
||||
GemRepoInfo() = default;
|
||||
GemRepoInfo(const QString& name, const QString& creator, const QString& summary, const QDateTime& lastUpdated, bool isEnabled);
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
bool operator<(const GemRepoInfo& gemRepoInfo) const;
|
||||
|
||||
QString m_path;
|
||||
QString m_name = "Unknown Gem Repo Name";
|
||||
QString m_creator = "Unknown Creator";
|
||||
bool m_isEnabled = false; //! Is the repo currently enabled for this engine?
|
||||
QString m_summary = "No summary provided.";
|
||||
QString m_directoryLink;
|
||||
QString m_repoLink;
|
||||
QDateTime m_lastUpdated;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <GemRepo/GemRepoItemDelegate.h>
|
||||
#include <GemRepo/GemRepoModel.h>
|
||||
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemRepoItemDelegate::GemRepoItemDelegate(QAbstractItemModel* model, QObject* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
, m_model(model)
|
||||
{
|
||||
m_refreshIcon = QIcon(":/Refresh.svg").pixmap(s_refreshIconSize, s_refreshIconSize);
|
||||
m_editIcon = QIcon(":/Edit.svg").pixmap(s_iconSize, s_iconSize);
|
||||
m_deleteIcon = QIcon(":/Delete.svg").pixmap(s_iconSize, s_iconSize);
|
||||
}
|
||||
|
||||
void GemRepoItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
|
||||
{
|
||||
if (!modelIndex.isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QStyleOptionViewItem options(option);
|
||||
initStyleOption(&options, modelIndex);
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
QRect fullRect, itemRect, contentRect;
|
||||
CalcRects(options, fullRect, itemRect, contentRect);
|
||||
QRect buttonRect = CalcButtonRect(contentRect);
|
||||
|
||||
QFont standardFont(options.font);
|
||||
standardFont.setPixelSize(static_cast<int>(s_fontSize));
|
||||
QFontMetrics standardFontMetrics(standardFont);
|
||||
|
||||
painter->save();
|
||||
painter->setClipping(true);
|
||||
painter->setClipRect(fullRect);
|
||||
painter->setFont(standardFont);
|
||||
painter->setPen(m_textColor);
|
||||
|
||||
// Draw background
|
||||
painter->fillRect(fullRect, m_backgroundColor);
|
||||
|
||||
// Draw item background
|
||||
const QColor itemBackgroundColor = options.state & QStyle::State_MouseOver ? m_itemBackgroundColor.lighter(120) : m_itemBackgroundColor;
|
||||
painter->fillRect(itemRect, itemBackgroundColor);
|
||||
|
||||
// Draw border
|
||||
if (options.state & QStyle::State_Selected)
|
||||
{
|
||||
painter->save();
|
||||
QPen borderPen(m_borderColor);
|
||||
borderPen.setWidth(s_borderWidth);
|
||||
painter->setPen(borderPen);
|
||||
painter->drawRect(itemRect);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
// Repo enabled
|
||||
DrawButton(painter, buttonRect, modelIndex);
|
||||
|
||||
// Repo name
|
||||
QString repoName = GemRepoModel::GetName(modelIndex);
|
||||
repoName = QFontMetrics(standardFont).elidedText(repoName, Qt::TextElideMode::ElideRight, s_nameMaxWidth);
|
||||
|
||||
QRect repoNameRect = GetTextRect(standardFont, repoName, s_fontSize);
|
||||
int currentHorizontalOffset = buttonRect.left() + s_buttonWidth + s_buttonSpacing;
|
||||
repoNameRect.moveTo(currentHorizontalOffset, contentRect.center().y() - repoNameRect.height() / 2);
|
||||
repoNameRect = painter->boundingRect(repoNameRect, Qt::TextSingleLine, repoName);
|
||||
|
||||
painter->drawText(repoNameRect, Qt::TextSingleLine, repoName);
|
||||
|
||||
// Rem repo creator
|
||||
QString repoCreator = GemRepoModel::GetCreator(modelIndex);
|
||||
repoCreator = standardFontMetrics.elidedText(repoCreator, Qt::TextElideMode::ElideRight, s_creatorMaxWidth);
|
||||
|
||||
QRect repoCreatorRect = GetTextRect(standardFont, repoCreator, s_fontSize);
|
||||
currentHorizontalOffset += s_nameMaxWidth + s_contentSpacing;
|
||||
repoCreatorRect.moveTo(currentHorizontalOffset, contentRect.center().y() - repoCreatorRect.height() / 2);
|
||||
repoCreatorRect = painter->boundingRect(repoCreatorRect, Qt::TextSingleLine, repoCreator);
|
||||
|
||||
painter->drawText(repoCreatorRect, Qt::TextSingleLine, repoCreator);
|
||||
|
||||
// Repo update
|
||||
QString repoUpdatedDate = GemRepoModel::GetLastUpdated(modelIndex).toString("dd/MM/yyyy hh:mmap");
|
||||
repoUpdatedDate = standardFontMetrics.elidedText(repoUpdatedDate, Qt::TextElideMode::ElideRight, s_updatedMaxWidth);
|
||||
|
||||
QRect repoUpdatedDateRect = GetTextRect(standardFont, repoUpdatedDate, s_fontSize);
|
||||
currentHorizontalOffset += s_creatorMaxWidth + s_contentSpacing;
|
||||
repoUpdatedDateRect.moveTo(currentHorizontalOffset, contentRect.center().y() - repoUpdatedDateRect.height() / 2);
|
||||
repoUpdatedDateRect = painter->boundingRect(repoUpdatedDateRect, Qt::TextSingleLine, repoUpdatedDate);
|
||||
|
||||
painter->drawText(repoUpdatedDateRect, Qt::TextSingleLine, repoUpdatedDate);
|
||||
|
||||
// Draw refresh button
|
||||
painter->drawPixmap(
|
||||
repoUpdatedDateRect.left() + repoUpdatedDateRect.width() + s_refreshIconSpacing,
|
||||
contentRect.center().y() - s_refreshIconSize / 3, // Dividing size by 3 centers much better
|
||||
m_refreshIcon);
|
||||
|
||||
if (options.state & QStyle::State_MouseOver)
|
||||
{
|
||||
DrawEditButtons(painter, contentRect);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QSize GemRepoItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
|
||||
{
|
||||
QStyleOptionViewItem options(option);
|
||||
initStyleOption(&options, modelIndex);
|
||||
|
||||
int marginsHorizontal = s_itemMargins.left() + s_itemMargins.right() + s_contentMargins.left() + s_contentMargins.right();
|
||||
return QSize(marginsHorizontal + s_buttonWidth + s_buttonSpacing + s_nameMaxWidth + s_creatorMaxWidth + s_updatedMaxWidth + s_contentSpacing * 3, s_height);
|
||||
}
|
||||
|
||||
bool GemRepoItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex)
|
||||
{
|
||||
if (!modelIndex.isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::KeyPress)
|
||||
{
|
||||
auto keyEvent = static_cast<const QKeyEvent*>(event);
|
||||
if (keyEvent->key() == Qt::Key_Space)
|
||||
{
|
||||
const bool isAdded = GemRepoModel::IsEnabled(modelIndex);
|
||||
GemRepoModel::SetEnabled(*model, modelIndex, !isAdded);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
|
||||
QRect fullRect, itemRect, contentRect;
|
||||
CalcRects(option, fullRect, itemRect, contentRect);
|
||||
const QRect buttonRect = CalcButtonRect(contentRect);
|
||||
|
||||
if (buttonRect.contains(mouseEvent->pos()))
|
||||
{
|
||||
const bool isAdded = GemRepoModel::IsEnabled(modelIndex);
|
||||
GemRepoModel::SetEnabled(*model, modelIndex, !isAdded);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
|
||||
}
|
||||
|
||||
void GemRepoItemDelegate::CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const
|
||||
{
|
||||
outFullRect = QRect(option.rect);
|
||||
outItemRect = QRect(outFullRect.adjusted(s_itemMargins.left(), s_itemMargins.top(), -s_itemMargins.right(), -s_itemMargins.bottom()));
|
||||
outContentRect = QRect(outItemRect.adjusted(s_contentMargins.left(), s_contentMargins.top(), -s_contentMargins.right(), -s_contentMargins.bottom()));
|
||||
}
|
||||
|
||||
QRect GemRepoItemDelegate::GetTextRect(QFont& font, const QString& text, qreal fontSize) const
|
||||
{
|
||||
font.setPixelSize(static_cast<int>(fontSize));
|
||||
return QFontMetrics(font).boundingRect(text);
|
||||
}
|
||||
|
||||
QRect GemRepoItemDelegate::CalcButtonRect(const QRect& contentRect) const
|
||||
{
|
||||
const QPoint topLeft = QPoint(contentRect.left(), contentRect.top() + contentRect.height() / 2 - s_buttonHeight / 2);
|
||||
const QSize size = QSize(s_buttonWidth, s_buttonHeight);
|
||||
return QRect(topLeft, size);
|
||||
}
|
||||
|
||||
void GemRepoItemDelegate::DrawButton(QPainter* painter, const QRect& buttonRect, const QModelIndex& modelIndex) const
|
||||
{
|
||||
painter->save();
|
||||
QPoint circleCenter;
|
||||
|
||||
const bool isEnabled = GemRepoModel::IsEnabled(modelIndex);
|
||||
if (isEnabled)
|
||||
{
|
||||
painter->setBrush(m_buttonEnabledColor);
|
||||
painter->setPen(m_buttonEnabledColor);
|
||||
|
||||
circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius + 1, 1);
|
||||
}
|
||||
|
||||
// Rounded rect
|
||||
painter->drawRoundedRect(buttonRect, s_buttonBorderRadius, s_buttonBorderRadius);
|
||||
|
||||
// Circle
|
||||
painter->setBrush(m_textColor);
|
||||
painter->drawEllipse(circleCenter, s_buttonCircleRadius, s_buttonCircleRadius);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void GemRepoItemDelegate::DrawEditButtons(QPainter* painter, const QRect& contentRect) const
|
||||
{
|
||||
painter->drawPixmap(contentRect.right() - s_iconSize * 2 - s_iconSpacing, contentRect.center().y() - s_iconSize / 2, m_editIcon);
|
||||
painter->drawPixmap(contentRect.right() - s_iconSize, contentRect.center().y() - s_iconSize / 2, m_deleteIcon);
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QStyledItemDelegate>
|
||||
#include <GemRepo/GemRepoInfo.h>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
|
||||
QT_FORWARD_DECLARE_CLASS(QEvent)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemRepoItemDelegate
|
||||
: public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemRepoItemDelegate(QAbstractItemModel* model, QObject* parent = nullptr);
|
||||
~GemRepoItemDelegate() = 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
|
||||
const QColor m_textColor = QColor("#FFFFFF");
|
||||
const QColor m_backgroundColor = QColor("#333333"); // Outside of the actual repo item
|
||||
const QColor m_itemBackgroundColor = QColor("#404040"); // Background color of the repo item
|
||||
const QColor m_borderColor = QColor("#1E70EB");
|
||||
const QColor m_buttonEnabledColor = QColor("#1E70EB");
|
||||
|
||||
// Item
|
||||
inline constexpr static int s_height = 72; // Repo item total height
|
||||
inline constexpr static qreal s_fontSize = 12.0;
|
||||
|
||||
// Margin and borders
|
||||
inline constexpr static QMargins s_itemMargins = QMargins(/*left=*/0, /*top=*/8, /*right=*/60, /*bottom=*/8); // Item border distances
|
||||
inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/20, /*top=*/20, /*right=*/20, /*bottom=*/20); // Distances of the elements within an item to the item borders
|
||||
inline constexpr static int s_borderWidth = 4;
|
||||
|
||||
// Content
|
||||
inline constexpr static int s_contentSpacing = 5;
|
||||
inline constexpr static int s_nameMaxWidth = 145;
|
||||
inline constexpr static int s_creatorMaxWidth = 115;
|
||||
inline constexpr static int s_updatedMaxWidth = 125;
|
||||
|
||||
// Button
|
||||
inline constexpr static int s_buttonWidth = 32;
|
||||
inline constexpr static int s_buttonHeight = 16;
|
||||
inline constexpr static int s_buttonBorderRadius = 8;
|
||||
inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 2;
|
||||
inline constexpr static int s_buttonSpacing = 20;
|
||||
|
||||
// Icon
|
||||
inline constexpr static int s_iconSize = 24;
|
||||
inline constexpr static int s_iconSpacing = 16;
|
||||
inline constexpr static int s_refreshIconSize = 14;
|
||||
inline constexpr static int s_refreshIconSpacing = 10;
|
||||
|
||||
protected:
|
||||
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;
|
||||
void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
void DrawEditButtons(QPainter* painter, const QRect& contentRect) const;
|
||||
|
||||
QAbstractItemModel* m_model = nullptr;
|
||||
|
||||
QPixmap m_refreshIcon;
|
||||
QPixmap m_editIcon;
|
||||
QPixmap m_deleteIcon;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <GemRepo/GemRepoListView.h>
|
||||
#include <GemRepo/GemRepoItemDelegate.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemRepoListView::GemRepoListView(QAbstractItemModel* model, QWidget* parent)
|
||||
: QListView(parent)
|
||||
{
|
||||
setObjectName("gemRepoListView");
|
||||
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
|
||||
setModel(model);
|
||||
setItemDelegate(new GemRepoItemDelegate(model, this));
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QListView>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemRepoListView
|
||||
: public QListView
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemRepoListView(QAbstractItemModel* model, QWidget* parent = nullptr);
|
||||
~GemRepoListView() = default;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <GemRepo/GemRepoModel.h>
|
||||
|
||||
#include <QItemSelectionModel>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemRepoModel::GemRepoModel(QObject* parent)
|
||||
: QStandardItemModel(parent)
|
||||
{
|
||||
m_selectionModel = new QItemSelectionModel(this, parent);
|
||||
}
|
||||
|
||||
QItemSelectionModel* GemRepoModel::GetSelectionModel() const
|
||||
{
|
||||
return m_selectionModel;
|
||||
}
|
||||
|
||||
void GemRepoModel::AddGemRepo(const GemRepoInfo& gemRepoInfo)
|
||||
{
|
||||
QStandardItem* item = new QStandardItem();
|
||||
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
|
||||
|
||||
item->setData(gemRepoInfo.m_name, RoleName);
|
||||
item->setData(gemRepoInfo.m_creator, RoleCreator);
|
||||
item->setData(gemRepoInfo.m_summary, RoleSummary);
|
||||
item->setData(gemRepoInfo.m_isEnabled, RoleIsEnabled);
|
||||
item->setData(gemRepoInfo.m_directoryLink, RoleDirectoryLink);
|
||||
item->setData(gemRepoInfo.m_repoLink, RoleRepoLink);
|
||||
item->setData(gemRepoInfo.m_lastUpdated, RoleLastUpdated);
|
||||
item->setData(gemRepoInfo.m_path, RolePath);
|
||||
|
||||
appendRow(item);
|
||||
}
|
||||
|
||||
void GemRepoModel::Clear()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
QString GemRepoModel::GetName(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleName).toString();
|
||||
}
|
||||
|
||||
QString GemRepoModel::GetCreator(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleCreator).toString();
|
||||
}
|
||||
|
||||
QString GemRepoModel::GetSummary(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleSummary).toString();
|
||||
}
|
||||
|
||||
QString GemRepoModel::GetDirectoryLink(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleDirectoryLink).toString();
|
||||
}
|
||||
|
||||
QString GemRepoModel::GetRepoLink(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleRepoLink).toString();
|
||||
}
|
||||
|
||||
QDateTime GemRepoModel::GetLastUpdated(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleLastUpdated).toDateTime();
|
||||
}
|
||||
|
||||
QString GemRepoModel::GetPath(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RolePath).toString();
|
||||
}
|
||||
|
||||
bool GemRepoModel::IsEnabled(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleIsEnabled).toBool();
|
||||
}
|
||||
|
||||
void GemRepoModel::SetEnabled(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isEnabled)
|
||||
{
|
||||
model.setData(modelIndex, isEnabled, RoleIsEnabled);
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QStandardItemModel>
|
||||
#include <GemRepo/GemRepoInfo.h>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemRepoModel
|
||||
: public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemRepoModel(QObject* parent = nullptr);
|
||||
QItemSelectionModel* GetSelectionModel() const;
|
||||
|
||||
void AddGemRepo(const GemRepoInfo& gemInfo);
|
||||
void Clear();
|
||||
|
||||
static QString GetName(const QModelIndex& modelIndex);
|
||||
static QString GetCreator(const QModelIndex& modelIndex);
|
||||
static QString GetSummary(const QModelIndex& modelIndex);
|
||||
static QString GetDirectoryLink(const QModelIndex& modelIndex);
|
||||
static QString GetRepoLink(const QModelIndex& modelIndex);
|
||||
static QDateTime GetLastUpdated(const QModelIndex& modelIndex);
|
||||
static QString GetPath(const QModelIndex& modelIndex);
|
||||
|
||||
static bool IsEnabled(const QModelIndex& modelIndex);
|
||||
static void SetEnabled(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isEnabled);
|
||||
|
||||
private:
|
||||
enum UserRole
|
||||
{
|
||||
RoleName = Qt::UserRole,
|
||||
RoleCreator,
|
||||
RoleSummary,
|
||||
RoleIsEnabled,
|
||||
RoleDirectoryLink,
|
||||
RoleRepoLink,
|
||||
RoleLastUpdated,
|
||||
RolePath
|
||||
};
|
||||
|
||||
QItemSelectionModel* m_selectionModel = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <GemRepo/GemRepoScreen.h>
|
||||
#include <GemRepo/GemRepoItemDelegate.h>
|
||||
#include <GemRepo/GemRepoListView.h>
|
||||
#include <GemRepo/GemRepoModel.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
#include <QLabel>
|
||||
#include <QHeaderView>
|
||||
#include <QTableWidget>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemRepoScreen::GemRepoScreen(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
m_gemRepoModel = new GemRepoModel(this);
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
vLayout->setMargin(0);
|
||||
vLayout->setSpacing(0);
|
||||
setLayout(vLayout);
|
||||
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
hLayout->setMargin(0);
|
||||
hLayout->setSpacing(0);
|
||||
vLayout->addLayout(hLayout);
|
||||
|
||||
hLayout->addSpacing(60);
|
||||
|
||||
m_gemRepoInspector = new QFrame(this);
|
||||
m_gemRepoInspector->setObjectName(tr("gemRepoInspector"));
|
||||
m_gemRepoInspector->setFixedWidth(240);
|
||||
|
||||
QVBoxLayout* middleVLayout = new QVBoxLayout();
|
||||
middleVLayout->setMargin(0);
|
||||
middleVLayout->setSpacing(0);
|
||||
|
||||
middleVLayout->addSpacing(30);
|
||||
|
||||
QHBoxLayout* topMiddleHLayout = new QHBoxLayout();
|
||||
topMiddleHLayout->setMargin(0);
|
||||
topMiddleHLayout->setSpacing(0);
|
||||
|
||||
m_lastAllUpdateLabel = new QLabel(tr("Last Updated: Never"), this);
|
||||
m_lastAllUpdateLabel->setObjectName("gemRepoHeaderLabel");
|
||||
topMiddleHLayout->addWidget(m_lastAllUpdateLabel);
|
||||
|
||||
topMiddleHLayout->addSpacing(20);
|
||||
|
||||
m_AllUpdateButton = new QPushButton(QIcon(":/Refresh.svg"), tr("Update All"), this);
|
||||
m_AllUpdateButton->setObjectName("gemRepoHeaderRefreshButton");
|
||||
topMiddleHLayout->addWidget(m_AllUpdateButton);
|
||||
|
||||
topMiddleHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
|
||||
|
||||
m_AddRepoButton = new QPushButton(tr("Add Repository"), this);
|
||||
m_AddRepoButton->setObjectName("gemRepoHeaderAddButton");
|
||||
topMiddleHLayout->addWidget(m_AddRepoButton);
|
||||
|
||||
middleVLayout->addLayout(topMiddleHLayout);
|
||||
|
||||
middleVLayout->addSpacing(30);
|
||||
|
||||
// Create a QTableWidget just for its header
|
||||
// Using a seperate model allows the setup of a header exactly as needed
|
||||
m_gemRepoHeaderTable = new QTableWidget(this);
|
||||
m_gemRepoHeaderTable->setObjectName("gemRepoHeaderTable");
|
||||
m_gemRepoListHeader = m_gemRepoHeaderTable->horizontalHeader();
|
||||
m_gemRepoListHeader->setObjectName("gemRepoListHeader");
|
||||
m_gemRepoListHeader->setSectionResizeMode(QHeaderView::ResizeMode::Fixed);
|
||||
|
||||
// Insert columns so the header labels will show up
|
||||
m_gemRepoHeaderTable->insertColumn(0);
|
||||
m_gemRepoHeaderTable->insertColumn(1);
|
||||
m_gemRepoHeaderTable->insertColumn(2);
|
||||
m_gemRepoHeaderTable->insertColumn(3);
|
||||
m_gemRepoHeaderTable->setHorizontalHeaderLabels({ tr("Enabled"), tr("Repository Name"), tr("Creator"), tr("Updated") });
|
||||
|
||||
const int headerExtraMargin = 10;
|
||||
m_gemRepoListHeader->resizeSection(0, GemRepoItemDelegate::s_buttonWidth + GemRepoItemDelegate::s_buttonSpacing - 3);
|
||||
m_gemRepoListHeader->resizeSection(1, GemRepoItemDelegate::s_nameMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
|
||||
m_gemRepoListHeader->resizeSection(2, GemRepoItemDelegate::s_creatorMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
|
||||
m_gemRepoListHeader->resizeSection(3, GemRepoItemDelegate::s_updatedMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
|
||||
|
||||
// Required to set stylesheet in code as it will not be respected if set in qss
|
||||
m_gemRepoHeaderTable->horizontalHeader()->setStyleSheet("QHeaderView::section { background-color:transparent; color:white; font-size:12px; text-align:left; border-style:none; }");
|
||||
middleVLayout->addWidget(m_gemRepoHeaderTable);
|
||||
|
||||
m_gemRepoListView = new GemRepoListView(m_gemRepoModel, this);
|
||||
middleVLayout->addWidget(m_gemRepoListView);
|
||||
|
||||
hLayout->addLayout(middleVLayout);
|
||||
hLayout->addWidget(m_gemRepoInspector);
|
||||
|
||||
Reinit();
|
||||
}
|
||||
|
||||
void GemRepoScreen::Reinit()
|
||||
{
|
||||
m_gemRepoModel->clear();
|
||||
FillModel();
|
||||
|
||||
// Select the first entry after everything got correctly sized
|
||||
QTimer::singleShot(200, [=]{
|
||||
QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0);
|
||||
m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
|
||||
});
|
||||
}
|
||||
|
||||
void GemRepoScreen::FillModel()
|
||||
{
|
||||
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos();
|
||||
if (allGemRepoInfosResult.IsSuccess())
|
||||
{
|
||||
// Add all available repos to the model
|
||||
const QVector<GemRepoInfo> allGemRepoInfos = allGemRepoInfosResult.GetValue();
|
||||
for (const GemRepoInfo& gemRepoInfo : allGemRepoInfos)
|
||||
{
|
||||
m_gemRepoModel->AddGemRepo(gemRepoInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
ProjectManagerScreen GemRepoScreen::GetScreenEnum()
|
||||
{
|
||||
return ProjectManagerScreen::GemRepos;
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QLabel)
|
||||
QT_FORWARD_DECLARE_CLASS(QPushButton)
|
||||
QT_FORWARD_DECLARE_CLASS(QHeaderView)
|
||||
QT_FORWARD_DECLARE_CLASS(QTableWidget)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
QT_FORWARD_DECLARE_CLASS(GemRepoListView)
|
||||
QT_FORWARD_DECLARE_CLASS(GemRepoModel)
|
||||
|
||||
class GemRepoScreen
|
||||
: public ScreenWidget
|
||||
{
|
||||
public:
|
||||
explicit GemRepoScreen(QWidget* parent = nullptr);
|
||||
~GemRepoScreen() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
void Reinit();
|
||||
|
||||
GemRepoModel* GetGemRepoModel() const { return m_gemRepoModel; }
|
||||
|
||||
private:
|
||||
void FillModel();
|
||||
|
||||
QTableWidget* m_gemRepoHeaderTable = nullptr;
|
||||
QHeaderView* m_gemRepoListHeader = nullptr;
|
||||
GemRepoListView* m_gemRepoListView = nullptr;
|
||||
QFrame* m_gemRepoInspector = nullptr;
|
||||
GemRepoModel* m_gemRepoModel = nullptr;
|
||||
|
||||
QLabel* m_lastAllUpdateLabel;
|
||||
QPushButton* m_AllUpdateButton;
|
||||
QPushButton* m_AddRepoButton;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -22,7 +22,7 @@ namespace O3DE::ProjectManager
|
||||
QVector<ProjectManagerScreen> screenEnums =
|
||||
{
|
||||
ProjectManagerScreen::Projects,
|
||||
ProjectManagerScreen::EngineSettings,
|
||||
ProjectManagerScreen::Engine,
|
||||
ProjectManagerScreen::CreateProject,
|
||||
ProjectManagerScreen::UpdateProject
|
||||
};
|
||||
|
||||
@@ -912,4 +912,45 @@ namespace O3DE::ProjectManager
|
||||
return AZ::Success(AZStd::move(templates));
|
||||
}
|
||||
}
|
||||
|
||||
GemRepoInfo PythonBindings::GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath)
|
||||
{
|
||||
/* Placeholder Logic */
|
||||
(void)path;
|
||||
(void)pyEnginePath;
|
||||
|
||||
return GemRepoInfo();
|
||||
}
|
||||
|
||||
//#define MOCK_GEM_REPO_INFO true
|
||||
|
||||
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> PythonBindings::GetAllGemRepoInfos()
|
||||
{
|
||||
QVector<GemRepoInfo> gemRepos;
|
||||
|
||||
#ifndef MOCK_GEM_REPO_INFO
|
||||
auto result = ExecuteWithLockErrorHandling(
|
||||
[&]
|
||||
{
|
||||
/* Placeholder Logic, o3de scripts need method added
|
||||
*
|
||||
for (auto path : m_manifest.attr("get_gem_repos")())
|
||||
{
|
||||
gemRepos.push_back(GemRepoInfoFromPath(path, pybind11::none()));
|
||||
}
|
||||
*
|
||||
*/
|
||||
});
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
return AZ::Failure<AZStd::string>(result.GetError().c_str());
|
||||
}
|
||||
#else
|
||||
gemRepos.push_back(GemRepoInfo("JohnCreates", "John Smith", "", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true));
|
||||
gemRepos.push_back(GemRepoInfo("JanesGems", "Jane Doe", "", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false));
|
||||
#endif // MOCK_GEM_REPO_INFO
|
||||
|
||||
std::sort(gemRepos.begin(), gemRepos.end());
|
||||
return AZ::Success(AZStd::move(gemRepos));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,12 +56,16 @@ namespace O3DE::ProjectManager
|
||||
// ProjectTemplate
|
||||
AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates(const QString& projectPath = {}) override;
|
||||
|
||||
// Gem Repos
|
||||
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() override;
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(PythonBindings);
|
||||
|
||||
AZ::Outcome<void, AZStd::string> ExecuteWithLockErrorHandling(AZStd::function<void()> executionCallback);
|
||||
bool ExecuteWithLock(AZStd::function<void()> executionCallback);
|
||||
GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
|
||||
GemRepoInfo GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath);
|
||||
ProjectInfo ProjectInfoFromPath(pybind11::handle path);
|
||||
ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
|
||||
bool RegisterThisEngine();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <GemCatalog/GemInfo.h>
|
||||
#include <ProjectInfo.h>
|
||||
#include <ProjectTemplateInfo.h>
|
||||
#include <GemRepo/GemRepoInfo.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -56,14 +57,14 @@ namespace O3DE::ProjectManager
|
||||
|
||||
/**
|
||||
* Get info about a Gem
|
||||
* @param path the absolute path to the Gem
|
||||
* @param projectPath the absolute path to the Gem
|
||||
* @return an outcome with GemInfo on success
|
||||
*/
|
||||
virtual AZ::Outcome<GemInfo> GetGemInfo(const QString& path, const QString& projectPath = {}) = 0;
|
||||
|
||||
/**
|
||||
* Get all available gem infos. This concatenates gems registered by the engine and the project.
|
||||
* @param path The absolute path to the project.
|
||||
* @param projectPath The absolute path to the project.
|
||||
* @return A list of gem infos.
|
||||
*/
|
||||
virtual AZ::Outcome<QVector<GemInfo>, AZStd::string> GetAllGemInfos(const QString& projectPath) = 0;
|
||||
@@ -155,6 +156,14 @@ namespace O3DE::ProjectManager
|
||||
* @return an outcome with ProjectTemplateInfos on success
|
||||
*/
|
||||
virtual AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates(const QString& projectPath = {}) = 0;
|
||||
|
||||
// Gem Repos
|
||||
|
||||
/**
|
||||
* Get all available gem repo infos. Gathers all repos registered with the engine.
|
||||
* @return A list of gem repo infos.
|
||||
*/
|
||||
virtual AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() = 0;
|
||||
};
|
||||
|
||||
using PythonBindingsInterface = AZ::Interface<IPythonBindings>;
|
||||
|
||||
@@ -23,7 +23,9 @@ namespace O3DE::ProjectManager
|
||||
Projects,
|
||||
UpdateProject,
|
||||
UpdateProjectSettings,
|
||||
EngineSettings
|
||||
Engine,
|
||||
EngineSettings,
|
||||
GemRepos
|
||||
};
|
||||
|
||||
static QHash<QString, ProjectManagerScreen> s_ProjectManagerStringNames = {
|
||||
@@ -34,7 +36,9 @@ namespace O3DE::ProjectManager
|
||||
{ "Projects", ProjectManagerScreen::Projects},
|
||||
{ "UpdateProject", ProjectManagerScreen::UpdateProject},
|
||||
{ "UpdateProjectSettings", ProjectManagerScreen::UpdateProjectSettings},
|
||||
{ "EngineSettings", ProjectManagerScreen::EngineSettings}
|
||||
{ "Engine", ProjectManagerScreen::Engine},
|
||||
{ "EngineSettings", ProjectManagerScreen::EngineSettings},
|
||||
{ "GemRepos", ProjectManagerScreen::GemRepos}
|
||||
};
|
||||
|
||||
// need to define qHash for ProjectManagerScreen when using scoped enums
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#include <GemCatalog/GemCatalogScreen.h>
|
||||
#include <ProjectsScreen.h>
|
||||
#include <UpdateProjectSettingsScreen.h>
|
||||
#include <EngineScreenCtrl.h>
|
||||
#include <EngineSettingsScreen.h>
|
||||
#include <GemRepo/GemRepoScreen.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -41,9 +43,15 @@ namespace O3DE::ProjectManager
|
||||
case (ProjectManagerScreen::UpdateProjectSettings):
|
||||
newScreen = new UpdateProjectSettingsScreen(parent);
|
||||
break;
|
||||
case (ProjectManagerScreen::Engine):
|
||||
newScreen = new EngineScreenCtrl(parent);
|
||||
break;
|
||||
case (ProjectManagerScreen::EngineSettings):
|
||||
newScreen = new EngineSettingsScreen(parent);
|
||||
break;
|
||||
case (ProjectManagerScreen::GemRepos):
|
||||
newScreen = new GemRepoScreen(parent);
|
||||
break;
|
||||
case (ProjectManagerScreen::Empty):
|
||||
default:
|
||||
newScreen = new ScreenWidget(parent);
|
||||
|
||||
@@ -56,6 +56,8 @@ set(FILES
|
||||
Source/ProjectsScreen.cpp
|
||||
Source/ProjectSettingsScreen.h
|
||||
Source/ProjectSettingsScreen.cpp
|
||||
Source/EngineScreenCtrl.h
|
||||
Source/EngineScreenCtrl.cpp
|
||||
Source/EngineSettingsScreen.h
|
||||
Source/EngineSettingsScreen.cpp
|
||||
Source/ProjectButtonWidget.h
|
||||
@@ -98,4 +100,14 @@ set(FILES
|
||||
Source/GemCatalog/GemRequirementListView.cpp
|
||||
Source/GemCatalog/GemSortFilterProxyModel.h
|
||||
Source/GemCatalog/GemSortFilterProxyModel.cpp
|
||||
Source/GemRepo/GemRepoScreen.h
|
||||
Source/GemRepo/GemRepoScreen.cpp
|
||||
Source/GemRepo/GemRepoInfo.h
|
||||
Source/GemRepo/GemRepoInfo.cpp
|
||||
Source/GemRepo/GemRepoItemDelegate.h
|
||||
Source/GemRepo/GemRepoItemDelegate.cpp
|
||||
Source/GemRepo/GemRepoListView.h
|
||||
Source/GemRepo/GemRepoListView.cpp
|
||||
Source/GemRepo/GemRepoModel.h
|
||||
Source/GemRepo/GemRepoModel.cpp
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user