Merge remote-tracking branch 'upstream/development' into nvsickle/OutlinerDuplicateEntryFixes
This commit is contained in:
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 for component mode collection queries.
|
||||
class ComponentModeCollectionInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(ComponentModeCollectionInterface, "{DFAA4450-BBCD-47C0-9B91-FEA2DBD9B152}");
|
||||
|
||||
virtual ~ComponentModeCollectionInterface() = default;
|
||||
|
||||
//! Retrieves the list of all Component types (usually one).
|
||||
//! @note If called outside of component mode, an empty vector will be returned.
|
||||
virtual AZStd::vector<AZ::Uuid> GetComponentTypes() const = 0;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
@@ -47,14 +47,6 @@ namespace AzToolsFramework
|
||||
|
||||
//! Retrieve the absolute path for the Asset Database Location
|
||||
virtual bool GetAbsoluteAssetDatabaseLocation(AZStd::string& /*result*/) { return false; }
|
||||
|
||||
//! Retrieve the absolute folder path to the current game's source assets (the ones that go into source control)
|
||||
//! This may include the current mod path, if a mod is being edited by the editor
|
||||
virtual const char* GetAbsoluteDevGameFolderPath() = 0;
|
||||
|
||||
//! Retrieve the absolute folder path to the current developer root ('dev'), which contains source artifacts
|
||||
//! and is generally checked into source control.
|
||||
virtual const char* GetAbsoluteDevRootFolderPath() = 0;
|
||||
|
||||
/// Convert a full source path like "c:\\dev\\gamename\\blah\\test.tga" into a relative product path.
|
||||
/// asset paths never mention their alias and are relative to the asset cache root
|
||||
|
||||
@@ -764,12 +764,6 @@ namespace AzToolsFramework
|
||||
//! Spawn asset browser for the appropriate asset types.
|
||||
virtual void BrowseForAssets(AssetBrowser::AssetSelectionModel& /*selection*/) = 0;
|
||||
|
||||
/// Allow interception of selection / left-mouse clicks in ObjectMode, for customizing selection behavior.
|
||||
virtual void HandleObjectModeSelection(const AZ::Vector2& /*point*/, int /*flags*/, bool& /*handled*/) {}
|
||||
|
||||
/// Allow interception of cursor, for customizing selection behavior.
|
||||
virtual void UpdateObjectModeCursor(AZ::u32& /*cursorId*/, AZStd::string& /*cursorStr*/) {}
|
||||
|
||||
/// Creates editor-side representation of an underlying entity.
|
||||
virtual void CreateEditorRepresentation(AZ::Entity* /*entity*/) { }
|
||||
|
||||
|
||||
+9
-9
@@ -22,22 +22,22 @@ namespace AzToolsFramework
|
||||
|
||||
virtual ~ViewportEditorModeTrackerInterface() = default;
|
||||
|
||||
//! Activates the specified editor mode for the specified viewport.
|
||||
//! Activates the specified editor mode for the specified viewport editor mode tracker.
|
||||
virtual AZ::Outcome<void, AZStd::string> ActivateMode(
|
||||
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0;
|
||||
const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo, ViewportEditorMode mode) = 0;
|
||||
|
||||
//! Deactivates the specified editor mode for the specified viewport.
|
||||
//! Deactivates the specified editor mode for the specified viewport editor mode tracker.
|
||||
virtual AZ::Outcome<void, AZStd::string> DeactivateMode(
|
||||
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0;
|
||||
const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo, 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;
|
||||
//! Attempts to retrieve the editor mode state for the specified viewport editor mode tracker, otherwise returns nullptr.
|
||||
virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo) const = 0;
|
||||
|
||||
//! Returns the number of viewports currently being tracked.
|
||||
//! Returns the number of viewport editor mode trackers.
|
||||
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;
|
||||
//! Returns true if viewport editor modes are being tracked for the specified od, otherwise false.
|
||||
virtual bool IsViewportModeTracked(const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo) const = 0;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
void ViewportEditorModeNotifications::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->EBus<ViewportEditorModeNotificationsBus>("ViewportEditorModeNotificationsBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "editor")
|
||||
->Event("OnEditorModeActivated", &ViewportEditorModeNotifications::OnEditorModeActivated)
|
||||
->Event("OnEditorModeDeactivated", &ViewportEditorModeNotifications::OnEditorModeDeactivated)
|
||||
;
|
||||
}
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
+11
-6
@@ -9,7 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/Event.h>
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
#include <AzFramework/Entity/EntityContextBus.h>
|
||||
#include <AzToolsFramework/ViewportUi/ViewportUiRequestBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -23,17 +23,19 @@ namespace AzToolsFramework
|
||||
Pick
|
||||
};
|
||||
|
||||
//! Viewport identifier and other relevant viewport data.
|
||||
struct ViewportEditorModeInfo
|
||||
//! Viewport editor mode tracker identifier and other relevant data.
|
||||
struct ViewportEditorModeTrackerInfo
|
||||
{
|
||||
using IdType = AzFramework::ViewportId;
|
||||
IdType m_id = ViewportUi::DefaultViewportId; //!< The unique identifier for a given viewport.
|
||||
using IdType = AzFramework::EntityContextId;
|
||||
IdType m_id = AzFramework::EntityContextId::CreateNull(); //!< The unique identifier for a given viewport editor mode tracker.
|
||||
};
|
||||
|
||||
//! Interface for the editor modes of a given viewport.
|
||||
class ViewportEditorModesInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(ViewportEditorModesInterface, "{2421496C-4A46-41C9-8AEF-AE2B6E43E6CF}");
|
||||
|
||||
virtual ~ViewportEditorModesInterface() = default;
|
||||
|
||||
//! Returns true if the specified editor mode is active, otherwise false.
|
||||
@@ -49,9 +51,12 @@ namespace AzToolsFramework
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
using BusIdType = ViewportEditorModeInfo::IdType;
|
||||
using BusIdType = ViewportEditorModeTrackerInfo::IdType;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AZ_RTTI(ViewportEditorModeNotifications, "{9469DE39-6C21-423C-94FA-EF3A9616B14F}", AZ::EBusTraits);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
//! 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)
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <AzToolsFramework/ToolsComponents/EditorAssetMimeDataContainer.h>
|
||||
#include <AzToolsFramework/ToolsComponents/ComponentAssetMimeDataContainer.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
|
||||
@@ -68,6 +69,7 @@
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiSystemComponent.h>
|
||||
#include <AzToolsFramework/Undo/UndoCacheInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <Entity/EntityUtilityComponent.h>
|
||||
|
||||
#include <QtWidgets/QMessageBox>
|
||||
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: 'QFileInfo::d_ptr': class 'QSharedDataPointer<QFileInfoPrivate>' needs to have dll-interface to be used by clients of class 'QFileInfo'
|
||||
@@ -251,6 +253,7 @@ namespace AzToolsFramework
|
||||
azrtti_typeid<EditorEntityContextComponent>(),
|
||||
azrtti_typeid<Components::EditorEntityUiSystemComponent>(),
|
||||
azrtti_typeid<FocusModeSystemComponent>(),
|
||||
azrtti_typeid<ContainerEntitySystemComponent>(),
|
||||
azrtti_typeid<SliceMetadataEntityContextComponent>(),
|
||||
azrtti_typeid<Prefab::PrefabSystemComponent>(),
|
||||
azrtti_typeid<EditorEntityFixupComponent>(),
|
||||
@@ -269,7 +272,8 @@ namespace AzToolsFramework
|
||||
azrtti_typeid<AzToolsFramework::EditorInteractionSystemComponent>(),
|
||||
azrtti_typeid<Components::EditorEntitySearchComponent>(),
|
||||
azrtti_typeid<Components::EditorIntersectorComponent>(),
|
||||
azrtti_typeid<AzToolsFramework::SliceRequestComponent>()
|
||||
azrtti_typeid<AzToolsFramework::SliceRequestComponent>(),
|
||||
azrtti_typeid<AzToolsFramework::EntityUtilityComponent>()
|
||||
});
|
||||
|
||||
return components;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
constexpr const char s_traceName[] = "ArchiveComponent";
|
||||
[[maybe_unused]] constexpr const char s_traceName[] = "ArchiveComponent";
|
||||
constexpr AZ::u32 s_compressionMethod = AZ::IO::INestedArchive::METHOD_DEFLATE;
|
||||
constexpr AZ::s32 s_compressionLevel = AZ::IO::INestedArchive::LEVEL_NORMAL;
|
||||
constexpr CompressionCodec::Codec s_compressionCodec = CompressionCodec::Codec::ZLIB;
|
||||
|
||||
@@ -354,26 +354,6 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
const char* AssetSystemComponent::GetAbsoluteDevGameFolderPath()
|
||||
{
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
if (fileIO)
|
||||
{
|
||||
return fileIO->GetAlias("@devassets@");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const char* AssetSystemComponent::GetAbsoluteDevRootFolderPath()
|
||||
{
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
if (fileIO)
|
||||
{
|
||||
return fileIO->GetAlias("@devroot@");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void AssetSystemComponent::OnSystemTick()
|
||||
{
|
||||
AssetSystemBus::ExecuteQueuedEvents();
|
||||
|
||||
@@ -56,8 +56,6 @@ namespace AzToolsFramework
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AzToolsFramework::AssetSystemRequestBus::Handler overrides
|
||||
bool GetAbsoluteAssetDatabaseLocation(AZStd::string& result) override;
|
||||
const char* GetAbsoluteDevGameFolderPath() override;
|
||||
const char* GetAbsoluteDevRootFolderPath() override;
|
||||
bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& outputPath) override;
|
||||
bool GenerateRelativeSourcePath(
|
||||
const AZStd::string& sourcePath, AZStd::string& outputPath, AZStd::string& watchFolder) override;
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace AzToolsFramework
|
||||
AssetEditorWidgetUserSettings::AssetEditorWidgetUserSettings()
|
||||
{
|
||||
char assetRoot[AZ_MAX_PATH_LEN] = { 0 };
|
||||
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", assetRoot, AZ_MAX_PATH_LEN);
|
||||
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", assetRoot, AZ_MAX_PATH_LEN);
|
||||
|
||||
m_lastSavePath = assetRoot;
|
||||
}
|
||||
@@ -410,7 +410,7 @@ namespace AzToolsFramework
|
||||
filter.append(ext);
|
||||
if (i < n - 1)
|
||||
{
|
||||
filter.append(", ");
|
||||
filter.append(" ");
|
||||
}
|
||||
}
|
||||
filter.append(")");
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <AzToolsFramework/AssetBundle/AssetBundleComponent.h>
|
||||
#include <AzToolsFramework/Component/EditorComponentAPIComponent.h>
|
||||
#include <AzToolsFramework/Component/EditorLevelComponentAPIComponent.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityActionComponent.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityFixupComponent.h>
|
||||
@@ -52,6 +53,7 @@
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerNullComponent.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserComponent.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h>
|
||||
#include <AzToolsFramework/Entity/EntityUtilityComponent.h>
|
||||
|
||||
AZ_DEFINE_BUDGET(AzToolsFramework);
|
||||
|
||||
@@ -70,6 +72,8 @@ namespace AzToolsFramework
|
||||
Components::EditorSelectionAccentSystemComponent::CreateDescriptor(),
|
||||
EditorEntityContextComponent::CreateDescriptor(),
|
||||
EditorEntityFixupComponent::CreateDescriptor(),
|
||||
EntityUtilityComponent::CreateDescriptor(),
|
||||
ContainerEntitySystemComponent::CreateDescriptor(),
|
||||
FocusModeSystemComponent::CreateDescriptor(),
|
||||
SliceMetadataEntityContextComponent::CreateDescriptor(),
|
||||
SliceRequestComponent::CreateDescriptor(),
|
||||
|
||||
+8
-17
@@ -203,6 +203,12 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::vector<AZ::Uuid> ComponentModeCollection::GetComponentTypes() const
|
||||
{
|
||||
// If in component mode, return the active component types, otherwise return an empty vector
|
||||
return InComponentMode() ? m_activeComponentTypes : AZStd::vector<AZ::Uuid>{};
|
||||
}
|
||||
|
||||
void ComponentModeCollection::BeginComponentMode()
|
||||
{
|
||||
m_selectedComponentModeIndex = 0;
|
||||
@@ -211,14 +217,7 @@ namespace AzToolsFramework
|
||||
|
||||
// notify listeners the editor has entered ComponentMode - listeners may
|
||||
// wish to modify state to indicate this (e.g. appearance, functionality etc.)
|
||||
EditorComponentModeNotificationBus::Event(
|
||||
GetEntityContextId(), &EditorComponentModeNotifications::EnteredComponentMode,
|
||||
m_activeComponentTypes);
|
||||
|
||||
// this call to activate the component mode editor state should eventually replace the bus call in
|
||||
// ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode
|
||||
// such that all of the notifications for activating/deactivating the different editor modes are in a central location
|
||||
m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component);
|
||||
m_viewportEditorModeTracker->ActivateMode({ GetEntityContextId() }, ViewportEditorMode::Component);
|
||||
|
||||
// enable actions for the first/primary ComponentMode
|
||||
// note: if multiple ComponentModes are activated at the same time, actions
|
||||
@@ -288,15 +287,7 @@ namespace AzToolsFramework
|
||||
|
||||
// notify listeners the editor has left ComponentMode - listeners may
|
||||
// wish to modify state to indicate this (e.g. appearance, functionality etc.)
|
||||
EditorComponentModeNotificationBus::Event(
|
||||
GetEntityContextId(),
|
||||
&EditorComponentModeNotifications::LeftComponentMode,
|
||||
m_activeComponentTypes);
|
||||
|
||||
// this call to deactivate the component mode editor state should eventually replace the bus call in
|
||||
// ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode
|
||||
// such that all of the notifications for activating/deactivating the different editor modes are in a central location
|
||||
m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component);
|
||||
m_viewportEditorModeTracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Component);
|
||||
|
||||
// clear stored modes and builders for this ComponentMode
|
||||
// TLDR: avoid 'use after free' error
|
||||
|
||||
+5
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzToolsFramework/API/ComponentModeCollectionInterface.h>
|
||||
#include <AzToolsFramework/ComponentMode/ComponentModeViewportUi.h>
|
||||
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
|
||||
|
||||
@@ -21,6 +22,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
/// Manages all individual ComponentModes for a single instance of Editor wide ComponentMode.
|
||||
class ComponentModeCollection
|
||||
: public ComponentModeCollectionInterface
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR_DECL
|
||||
@@ -89,6 +91,9 @@ namespace AzToolsFramework
|
||||
/// Called once each time a ComponentMode is added.
|
||||
void PopulateViewportUi();
|
||||
|
||||
// ComponentModeCollectionInterface overrides ...
|
||||
AZStd::vector<AZ::Uuid> GetComponentTypes() const override;
|
||||
|
||||
private:
|
||||
// Internal helper used by Select[|Prev|Next]ActiveComponentMode
|
||||
bool ActiveComponentModeChanged(const AZ::Uuid& previousComponentType);
|
||||
|
||||
+2
-14
@@ -24,18 +24,8 @@ namespace AzToolsFramework
|
||||
: public EditorComponentModeNotificationBus::Handler
|
||||
, public AZ::BehaviorEBusHandler
|
||||
{
|
||||
AZ_EBUS_BEHAVIOR_BINDER(EditorComponentModeNotificationBusHandler, "{AD2F4204-0913-4FC9-9A10-492538F60C70}", AZ::SystemAllocator,
|
||||
EnteredComponentMode, LeftComponentMode, ActiveComponentModeChanged);
|
||||
|
||||
void EnteredComponentMode(const AZStd::vector<AZ::Uuid>& componentTypes) override
|
||||
{
|
||||
Call(FN_EnteredComponentMode, componentTypes);
|
||||
}
|
||||
|
||||
void LeftComponentMode(const AZStd::vector<AZ::Uuid>& componentTypes) override
|
||||
{
|
||||
Call(FN_LeftComponentMode, componentTypes);
|
||||
}
|
||||
AZ_EBUS_BEHAVIOR_BINDER(
|
||||
EditorComponentModeNotificationBusHandler, "{AD2F4204-0913-4FC9-9A10-492538F60C70}", AZ::SystemAllocator, ActiveComponentModeChanged);
|
||||
|
||||
void ActiveComponentModeChanged(const AZ::Uuid& componentType) override
|
||||
{
|
||||
@@ -171,8 +161,6 @@ namespace AzToolsFramework
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "editor")
|
||||
->Handler<Internal::EditorComponentModeNotificationBusHandler>()
|
||||
->Event("EnteredComponentMode", &EditorComponentModeNotifications::EnteredComponentMode)
|
||||
->Event("LeftComponentMode", &EditorComponentModeNotifications::LeftComponentMode)
|
||||
->Event("ActiveComponentModeChanged", &EditorComponentModeNotifications::ActiveComponentModeChanged)
|
||||
;
|
||||
}
|
||||
|
||||
-42
@@ -238,12 +238,6 @@ namespace AzToolsFramework
|
||||
using BusIdType = AzFramework::EntityContextId;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
|
||||
/// Called when Editor enters ComponentMode - pass the list of all Component types (usually one).
|
||||
virtual void EnteredComponentMode(const AZStd::vector<AZ::Uuid>& componentTypes) = 0;
|
||||
|
||||
/// Called when Editor leaves ComponentMode - pass the list of all Component types (usually one).
|
||||
virtual void LeftComponentMode(const AZStd::vector<AZ::Uuid>& componentTypes) = 0;
|
||||
|
||||
/// Called when Tab is pressed to cycle the 'selected' ComponentMode (which shortcuts/actions are active).
|
||||
/// Also called when directly selecting a Component in the EntityOutliner.
|
||||
virtual void ActiveComponentModeChanged(const AZ::Uuid& /*componentType*/) {}
|
||||
@@ -255,42 +249,6 @@ namespace AzToolsFramework
|
||||
/// Type to inherit to implement EditorComponentModeNotifications.
|
||||
using EditorComponentModeNotificationBus = AZ::EBus<EditorComponentModeNotifications>;
|
||||
|
||||
/// Helper for EditorComponentModeNotifications to be used
|
||||
/// as a member instead of inheriting from EBus directly.
|
||||
class EditorComponentModeNotificationBusImpl
|
||||
: public EditorComponentModeNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
/// Set the function to be called when entering ComponentMode.
|
||||
void SetEnteredComponentModeFunc(
|
||||
const AZStd::function<void(const AZStd::vector<AZ::Uuid>&)>& enteredComponentModeFunc)
|
||||
{
|
||||
m_enteredComponentModeFunc = enteredComponentModeFunc;
|
||||
}
|
||||
|
||||
/// Set the function to be called when leaving ComponentMode.
|
||||
void SetLeftComponentModeFunc(
|
||||
const AZStd::function<void(const AZStd::vector<AZ::Uuid>&)>& leftComponentModeFunc)
|
||||
{
|
||||
m_leftComponentModeFunc = leftComponentModeFunc;
|
||||
}
|
||||
|
||||
private:
|
||||
// EditorComponentModeNotificationBus
|
||||
void EnteredComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes) override
|
||||
{
|
||||
m_enteredComponentModeFunc(componentModeTypes);
|
||||
}
|
||||
|
||||
void LeftComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes) override
|
||||
{
|
||||
m_leftComponentModeFunc(componentModeTypes);
|
||||
}
|
||||
|
||||
AZStd::function<void(const AZStd::vector<AZ::Uuid>&)> m_enteredComponentModeFunc; ///< Function to call when entering ComponentMode.
|
||||
AZStd::function<void(const AZStd::vector<AZ::Uuid>&)> m_leftComponentModeFunc; ///< Function to call when leaving ComponentMode.
|
||||
};
|
||||
|
||||
/// Helper to answer if the Editor is in ComponentMode or not.
|
||||
inline bool InComponentMode()
|
||||
{
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
#include <AzFramework/Entity/EntityContextBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! Outcome object that returns an error message in case of failure to allow caller to handle internal errors.
|
||||
using ContainerEntityOperationResult = AZ::Outcome<void, AZStd::string>;
|
||||
|
||||
//! ContainerEntityInterface
|
||||
//! An entity registered as Container is just like a regular entity when open. If its state is changed
|
||||
//! to closed, all descendants of the entity will be treated as part of the entity itself. Selecting any
|
||||
//! descendant will result in the container being selected, and descendants will be hidden until the
|
||||
//! container is opened.
|
||||
class ContainerEntityInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(ContainerEntityInterface, "{0A877C3A-726C-4FD2-BAFE-A2B9F1DE78E4}");
|
||||
|
||||
//! Registers the entity as a container. The container will be closed by default.
|
||||
//! @param entityId The entityId that will be registered as a container.
|
||||
virtual ContainerEntityOperationResult RegisterEntityAsContainer(AZ::EntityId entityId) = 0;
|
||||
|
||||
//! Unregisters the entity as a container.
|
||||
//! The system will retain the closed state in case the entity is registered again later, but
|
||||
//! if queried the entity will no longer behave as a container.
|
||||
//! @param entityId The entityId that will be unregistered as a container.
|
||||
virtual ContainerEntityOperationResult UnregisterEntityAsContainer(AZ::EntityId entityId) = 0;
|
||||
|
||||
//! Returns whether the entity id provided is registered as a container.
|
||||
virtual bool IsContainer(AZ::EntityId entityId) const = 0;
|
||||
|
||||
//! Sets the open state of the container entity provided.
|
||||
//! @param entityId The entityId whose open state will be set.
|
||||
//! @param open True if the container should be opened, false if it should be closed.
|
||||
//! @return An error message if the operation was invalid, success otherwise.
|
||||
virtual ContainerEntityOperationResult SetContainerOpen(AZ::EntityId entityId, bool open) = 0;
|
||||
|
||||
//! If the entity id provided is registered as a container, it returns whether it's open.
|
||||
//! @note the default value for non-containers is true, so this function can be called without
|
||||
//! verifying whether the entityId is registered as a container beforehand, since the container's
|
||||
//! open behavior is exactly the same as the one of a regular entity.
|
||||
//! @return False if the entityId is registered as a container, and its state is closed. True otherwise.
|
||||
virtual bool IsContainerOpen(AZ::EntityId entityId) const = 0;
|
||||
|
||||
//! Detects if one of the ancestors of entityId is a closed container entity.
|
||||
//! @return The highest closed entity container id if any, or entityId otherwise.
|
||||
virtual AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const = 0;
|
||||
|
||||
//! Clears all open state information for Container Entities for the EntityContextId provided.
|
||||
//! Used when context is switched, for example in the case of a new root prefab being loaded
|
||||
//! in place of an old one.
|
||||
//! @note Clear is meant to be called when no container is registered for the context provided.
|
||||
//! @return An error message if any container was registered for the context, success otherwise.
|
||||
virtual ContainerEntityOperationResult Clear(AzFramework::EntityContextId entityContextId) = 0;
|
||||
|
||||
//! Returns true if one of the ancestors of entityId is a closed container entity.
|
||||
virtual bool IsUnderClosedContainerEntity(AZ::EntityId entityId) const = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
#include <AzFramework/Entity/EntityContext.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! Used to notify changes of state for Container Entities.
|
||||
class ContainerEntityNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
using BusIdType = AzFramework::EntityContextId;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Triggered when a container entity status changes.
|
||||
//! @param entityId The entity whose status has changed.
|
||||
//! @param open The open state the container was changed to.
|
||||
virtual void OnContainerEntityStatusChanged([[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] bool open) {}
|
||||
|
||||
protected:
|
||||
~ContainerEntityNotifications() = default;
|
||||
};
|
||||
|
||||
using ContainerEntityNotificationBus = AZ::EBus<ContainerEntityNotifications>;
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h>
|
||||
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
void ContainerEntitySystemComponent::Activate()
|
||||
{
|
||||
AZ::Interface<ContainerEntityInterface>::Register(this);
|
||||
EditorEntityContextNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void ContainerEntitySystemComponent::Deactivate()
|
||||
{
|
||||
EditorEntityContextNotificationBus::Handler::BusDisconnect();
|
||||
AZ::Interface<ContainerEntityInterface>::Unregister(this);
|
||||
}
|
||||
|
||||
void ContainerEntitySystemComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context)
|
||||
{
|
||||
}
|
||||
|
||||
void ContainerEntitySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC_CE("ContainerEntityService"));
|
||||
}
|
||||
|
||||
ContainerEntityOperationResult ContainerEntitySystemComponent::RegisterEntityAsContainer(AZ::EntityId entityId)
|
||||
{
|
||||
if (IsContainer(entityId))
|
||||
{
|
||||
return AZ::Failure(AZStd::string(
|
||||
"ContainerEntitySystemComponent error - trying to register entity as container twice."));
|
||||
}
|
||||
|
||||
m_containers.insert(entityId);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
ContainerEntityOperationResult ContainerEntitySystemComponent::UnregisterEntityAsContainer(AZ::EntityId entityId)
|
||||
{
|
||||
if (!IsContainer(entityId))
|
||||
{
|
||||
return AZ::Failure(AZStd::string(
|
||||
"ContainerEntitySystemComponent error - trying to unregister entity that is not a container."));
|
||||
}
|
||||
|
||||
m_containers.erase(entityId);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
bool ContainerEntitySystemComponent::IsContainer(AZ::EntityId entityId) const
|
||||
{
|
||||
return m_containers.contains(entityId);
|
||||
}
|
||||
|
||||
ContainerEntityOperationResult ContainerEntitySystemComponent::SetContainerOpen(AZ::EntityId entityId, bool open)
|
||||
{
|
||||
if (!IsContainer(entityId))
|
||||
{
|
||||
return AZ::Failure(AZStd::string(
|
||||
"ContainerEntitySystemComponent error - cannot set open state of entity that was not registered as container."));
|
||||
}
|
||||
|
||||
if(open)
|
||||
{
|
||||
m_openContainers.insert(entityId);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_openContainers.erase(entityId);
|
||||
}
|
||||
|
||||
ContainerEntityNotificationBus::Broadcast(&ContainerEntityNotificationBus::Events::OnContainerEntityStatusChanged, entityId, open);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
bool ContainerEntitySystemComponent::IsContainerOpen(AZ::EntityId entityId) const
|
||||
{
|
||||
// Non-container entities behave the same as open containers. This saves the caller an additional check.
|
||||
if(!m_containers.contains(entityId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the entity is a container, return its state.
|
||||
return m_openContainers.contains(entityId);
|
||||
}
|
||||
|
||||
AZ::EntityId ContainerEntitySystemComponent::FindHighestSelectableEntity(AZ::EntityId entityId) const
|
||||
{
|
||||
if (!entityId.IsValid())
|
||||
{
|
||||
return entityId;
|
||||
}
|
||||
|
||||
// Return the highest closed container, or the entity if none is found.
|
||||
AZ::EntityId highestSelectableEntityId = entityId;
|
||||
|
||||
// Skip the queried entity, as we only want to check its ancestors.
|
||||
AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId);
|
||||
|
||||
// Go up the hierarchy until you hit the root
|
||||
while (entityId.IsValid())
|
||||
{
|
||||
if (!IsContainerOpen(entityId))
|
||||
{
|
||||
// If one of the ancestors is a container and it's closed, keep track of its id.
|
||||
// We only return of the higher closed container in the hierarchy.
|
||||
highestSelectableEntityId = entityId;
|
||||
}
|
||||
|
||||
AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId);
|
||||
}
|
||||
|
||||
return highestSelectableEntityId;
|
||||
}
|
||||
|
||||
void ContainerEntitySystemComponent::OnEntityStreamLoadSuccess()
|
||||
{
|
||||
// We don't yet support multiple entity contexts, so just use the default.
|
||||
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
Clear(editorEntityContextId);
|
||||
}
|
||||
|
||||
ContainerEntityOperationResult ContainerEntitySystemComponent::Clear(AzFramework::EntityContextId entityContextId)
|
||||
{
|
||||
// We don't yet support multiple entity contexts, so only clear the default.
|
||||
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
if (entityContextId != editorEntityContextId)
|
||||
{
|
||||
return AZ::Failure(AZStd::string(
|
||||
"Error in ContainerEntitySystemComponent::Clear - cannot clear non-default Entity Context!"));
|
||||
}
|
||||
|
||||
if (!m_containers.empty())
|
||||
{
|
||||
return AZ::Failure(AZStd::string(
|
||||
"Error in ContainerEntitySystemComponent::Clear - cannot clear container states if entities are still registered!"));
|
||||
}
|
||||
|
||||
m_openContainers.clear();
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
bool ContainerEntitySystemComponent::IsUnderClosedContainerEntity(AZ::EntityId entityId) const
|
||||
{
|
||||
if (!entityId.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip the queried entity, as we only want to check its ancestors.
|
||||
AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId);
|
||||
|
||||
// Go up the hierarchy until you hit the root.
|
||||
while (entityId.IsValid())
|
||||
{
|
||||
if (!IsContainerOpen(entityId))
|
||||
{
|
||||
// One of the ancestors is a container and it's closed.
|
||||
return true;
|
||||
}
|
||||
|
||||
AZ::EntityId parentId;
|
||||
AZ::TransformBus::EventResult(parentId, entityId, &AZ::TransformBus::Events::GetParentId);
|
||||
|
||||
if (parentId == entityId)
|
||||
{
|
||||
// In some circumstances, querying a root level entity with GetParentId will return
|
||||
// the entity itself instead of an invalid entityId.
|
||||
break;
|
||||
}
|
||||
|
||||
entityId = parentId;
|
||||
}
|
||||
|
||||
// All ancestors are either regular entities or open containers.
|
||||
return false;
|
||||
}
|
||||
|
||||
} // 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/Component/Component.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! System Component to track Container Entity registration and open state.
|
||||
//! An entity registered as Container is just like a regular entity when open. If its state is changed
|
||||
//! to closed, all descendants of the entity will be treated as part of the entity itself. Selecting any
|
||||
//! descendant will result in the container being selected, and descendants will be hidden until the
|
||||
//! container is opened.
|
||||
class ContainerEntitySystemComponent final
|
||||
: public AZ::Component
|
||||
, private ContainerEntityInterface
|
||||
, private EditorEntityContextNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(ContainerEntitySystemComponent, "{74349759-B36B-44A6-B89F-F45D7111DD11}");
|
||||
|
||||
ContainerEntitySystemComponent() = default;
|
||||
virtual ~ContainerEntitySystemComponent() = default;
|
||||
|
||||
// AZ::Component overrides ...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
|
||||
// ContainerEntityInterface overrides ...
|
||||
ContainerEntityOperationResult RegisterEntityAsContainer(AZ::EntityId entityId) override;
|
||||
ContainerEntityOperationResult UnregisterEntityAsContainer(AZ::EntityId entityId) override;
|
||||
bool IsContainer(AZ::EntityId entityId) const override;
|
||||
ContainerEntityOperationResult SetContainerOpen(AZ::EntityId entityId, bool open) override;
|
||||
bool IsContainerOpen(AZ::EntityId entityId) const override;
|
||||
AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const override;
|
||||
ContainerEntityOperationResult Clear(AzFramework::EntityContextId entityContextId) override;
|
||||
bool IsUnderClosedContainerEntity(AZ::EntityId entityId) const override;
|
||||
|
||||
// EditorEntityContextNotificationBus overrides ...
|
||||
void OnEntityStreamLoadSuccess() override;
|
||||
|
||||
private:
|
||||
AZStd::unordered_set<AZ::EntityId> m_containers; //!< All entities in this set are containers.
|
||||
AZStd::unordered_set<AZ::EntityId> m_openContainers; //!< All entities in this set are open containers.
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
@@ -39,7 +39,7 @@ namespace AzToolsFramework
|
||||
// the TraceContextLogFormatter.
|
||||
//
|
||||
// Usage example:
|
||||
// const char* gameFolder = m_context.pRC->GetSystemEnvironment()->pFileIO->GetAlias("@devassets@");
|
||||
// const char* gameFolder = m_context.pRC->GetSystemEnvironment()->pFileIO->GetAlias("@projectroot@");
|
||||
// AZ_TraceContext("Game folder", gameFolder);
|
||||
//
|
||||
// for (int i=0; i<subMeshCount; ++i)
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
#include <AzCore/RTTI/AttributeReader.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/Commands/EntityStateCommand.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/Slice/SliceMetadataEntityContextBus.h>
|
||||
#include <AzToolsFramework/Slice/SliceUtilities.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorLockComponentBus.h>
|
||||
@@ -588,15 +590,40 @@ namespace AzToolsFramework
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
// Detect if the Entity is Visible
|
||||
bool visible = false;
|
||||
EditorEntityInfoRequestBus::EventResult(
|
||||
visible, entityId, &EditorEntityInfoRequestBus::Events::IsVisible);
|
||||
|
||||
bool locked = false;
|
||||
EditorEntityInfoRequestBus::EventResult(
|
||||
locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked);
|
||||
if (!visible)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return visible && !locked;
|
||||
// Detect if the Entity is Locked
|
||||
bool locked = false;
|
||||
EditorEntityInfoRequestBus::EventResult(locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked);
|
||||
|
||||
if (locked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Detect if the Entity is part of the Editor Focus
|
||||
if (auto focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
!focusModeInterface->IsInFocusSubTree(entityId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Detect if the Entity is a descendant of a closed container
|
||||
if (auto containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
|
||||
containerEntityInterface->IsUnderClosedContainerEntity(entityId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void SetEntityLockStateRecursively(
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* 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 <sstream>
|
||||
#include <AzCore/JSON/rapidjson.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerializationSettings.h>
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
#include <AzFramework/Entity/EntityContext.h>
|
||||
#include <AzFramework/FileFunc/FileFunc.h>
|
||||
#include <AzToolsFramework/Entity/EntityUtilityComponent.h>
|
||||
#include <Entity/EditorEntityContextBus.h>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
void ComponentDetails::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<ComponentDetails>()
|
||||
->Field("TypeInfo", &ComponentDetails::m_typeInfo)
|
||||
->Field("BaseClasses", &ComponentDetails::m_baseClasses);
|
||||
|
||||
serializeContext->RegisterGenericType<AZStd::vector<ComponentDetails>>();
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<ComponentDetails>()
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "entity")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Property("TypeInfo", BehaviorValueProperty(&ComponentDetails::m_typeInfo))
|
||||
->Property("BaseClasses", BehaviorValueProperty(&ComponentDetails::m_baseClasses))
|
||||
->Method("__repr__", [](const ComponentDetails& obj)
|
||||
{
|
||||
std::ostringstream result;
|
||||
bool first = true;
|
||||
|
||||
for (const auto& baseClass : obj.m_baseClasses)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
result << ", ";
|
||||
}
|
||||
|
||||
first = false;
|
||||
result << baseClass.c_str();
|
||||
}
|
||||
|
||||
return AZStd::string::format("%s, Base Classes: <%s>", obj.m_typeInfo.c_str(), result.str().c_str());
|
||||
})
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::EntityId EntityUtilityComponent::CreateEditorReadyEntity(const AZStd::string& entityName)
|
||||
{
|
||||
auto* newEntity = m_entityContext->CreateEntity(entityName.c_str());
|
||||
|
||||
if (!newEntity)
|
||||
{
|
||||
AZ_Error("EditorEntityUtility", false, "Failed to create new entity %s", entityName.c_str());
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorEntityContextRequestBus::Events::AddRequiredComponents, *newEntity);
|
||||
|
||||
newEntity->Init();
|
||||
auto newEntityId = newEntity->GetId();
|
||||
|
||||
m_createdEntities.emplace_back(newEntityId);
|
||||
|
||||
return newEntityId;
|
||||
}
|
||||
|
||||
AZ::TypeId GetComponentTypeIdFromName(const AZStd::string& typeName)
|
||||
{
|
||||
// Try to create a TypeId first. We won't show any warnings if this fails as the input might be a class name instead
|
||||
AZ::TypeId typeId = AZ::TypeId::CreateStringPermissive(typeName.data());
|
||||
|
||||
// If the typeId is null, try a lookup by class name
|
||||
if (typeId.IsNull())
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
|
||||
auto typeNameCrc = AZ::Crc32(typeName.data());
|
||||
auto typeUuidList = serializeContext->FindClassId(typeNameCrc);
|
||||
|
||||
// TypeId is invalid or class name is invalid
|
||||
if (typeUuidList.empty())
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Provided type %s is either an invalid TypeId or does not match any class names", typeName.c_str());
|
||||
return AZ::TypeId::CreateNull();
|
||||
}
|
||||
|
||||
typeId = typeUuidList[0];
|
||||
}
|
||||
|
||||
return typeId;
|
||||
}
|
||||
|
||||
AZ::Component* FindComponentHelper(AZ::EntityId entityId, const AZ::TypeId& typeId, AZ::ComponentId componentId, bool createComponent = false)
|
||||
{
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, entityId);
|
||||
|
||||
if (!entity)
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Invalid entityId %s", entityId.ToString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AZ::Component* component = nullptr;
|
||||
if (componentId != AZ::InvalidComponentId)
|
||||
{
|
||||
component = entity->FindComponent(componentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
component = entity->FindComponent(typeId);
|
||||
}
|
||||
|
||||
if (!component && createComponent)
|
||||
{
|
||||
component = entity->CreateComponent(typeId);
|
||||
}
|
||||
|
||||
if (!component)
|
||||
{
|
||||
AZ_Error(
|
||||
"EntityUtilityComponent", false, "Failed to find component (%s) on entity %s (%s)",
|
||||
componentId != AZ::InvalidComponentId ? AZStd::to_string(componentId).c_str()
|
||||
: typeId.ToString<AZStd::string>().c_str(),
|
||||
entityId.ToString().c_str(),
|
||||
entity->GetName().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
AzFramework::BehaviorComponentId EntityUtilityComponent::GetOrAddComponentByTypeName(AZ::EntityId entityId, const AZStd::string& typeName)
|
||||
{
|
||||
AZ::TypeId typeId = GetComponentTypeIdFromName(typeName);
|
||||
|
||||
if (typeId.IsNull())
|
||||
{
|
||||
return AzFramework::BehaviorComponentId(AZ::InvalidComponentId);
|
||||
}
|
||||
|
||||
AZ::Component* component = FindComponentHelper(entityId, typeId, AZ::InvalidComponentId, true);
|
||||
|
||||
return component ? AzFramework::BehaviorComponentId(component->GetId()) :
|
||||
AzFramework::BehaviorComponentId(AZ::InvalidComponentId);
|
||||
}
|
||||
|
||||
bool EntityUtilityComponent::UpdateComponentForEntity(AZ::EntityId entityId, AzFramework::BehaviorComponentId componentId, const AZStd::string& json)
|
||||
{
|
||||
if (!componentId.IsValid())
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Invalid componentId passed to UpdateComponentForEntity");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::Component* component = FindComponentHelper(entityId, AZ::TypeId::CreateNull(), componentId);
|
||||
|
||||
if (!component)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
AZ::JsonDeserializerSettings settings = AZ::JsonDeserializerSettings{};
|
||||
settings.m_reporting = []([[maybe_unused]] AZStd::string_view message, ResultCode result, AZStd::string_view) -> auto
|
||||
{
|
||||
if (result.GetProcessing() == Processing::Halted)
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "JSON %s\n", message.data());
|
||||
}
|
||||
else if (result.GetOutcome() > Outcomes::PartialDefaults)
|
||||
{
|
||||
AZ_Warning("EntityUtilityComponent", false, "JSON %s\n", message.data());
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
rapidjson::Document doc;
|
||||
doc.Parse<rapidjson::kParseCommentsFlag>(json.data(), json.size());
|
||||
ResultCode resultCode = AZ::JsonSerialization::Load(*component, doc, settings);
|
||||
|
||||
return resultCode.GetProcessing() != Processing::Halted;
|
||||
}
|
||||
|
||||
AZStd::string EntityUtilityComponent::GetComponentDefaultJson(const AZStd::string& typeName)
|
||||
{
|
||||
AZ::TypeId typeId = GetComponentTypeIdFromName(typeName);
|
||||
|
||||
if (typeId.IsNull())
|
||||
{
|
||||
// GetComponentTypeIdFromName already does error handling
|
||||
return "";
|
||||
}
|
||||
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
|
||||
const AZ::SerializeContext::ClassData* classData = serializeContext->FindClassData(typeId);
|
||||
|
||||
if (!classData)
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Failed to find ClassData for typeId %s (%s)", typeId.ToString<AZStd::string>().c_str(), typeName.c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
void* component = classData->m_factory->Create("Component");
|
||||
rapidjson::Document document;
|
||||
AZ::JsonSerializerSettings settings;
|
||||
settings.m_keepDefaults = true;
|
||||
|
||||
auto resultCode = AZ::JsonSerialization::Store(document, document.GetAllocator(), component, nullptr, typeId, settings);
|
||||
|
||||
// Clean up the allocated component ASAP, we don't need it anymore
|
||||
classData->m_factory->Destroy(component);
|
||||
|
||||
if (resultCode.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Failed to serialize component to json (%s): %s",
|
||||
typeName.c_str(), resultCode.ToString(typeName).c_str())
|
||||
return "";
|
||||
}
|
||||
|
||||
AZStd::string jsonString;
|
||||
AZ::Outcome<void, AZStd::string> outcome = AZ::JsonSerializationUtils::WriteJsonString(document, jsonString);
|
||||
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Failed to write component json to string: %s", outcome.GetError().c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
AZStd::vector<ComponentDetails> EntityUtilityComponent::FindMatchingComponents(const AZStd::string& searchTerm)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
|
||||
if (m_typeInfo.empty())
|
||||
{
|
||||
serializeContext->EnumerateDerived<AZ::Component>(
|
||||
[this, serializeContext](const AZ::SerializeContext::ClassData* classData, const AZ::Uuid& /*typeId*/)
|
||||
{
|
||||
auto& typeInfo = m_typeInfo.emplace_back(classData->m_typeId, classData->m_name, AZStd::vector<AZStd::string>{});
|
||||
|
||||
serializeContext->EnumerateBase(
|
||||
[&typeInfo](const AZ::SerializeContext::ClassData* classData, const AZ::Uuid&)
|
||||
{
|
||||
if (classData)
|
||||
{
|
||||
AZStd::get<2>(typeInfo).emplace_back(classData->m_name);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
classData->m_typeId);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
AZStd::vector<ComponentDetails> matches;
|
||||
|
||||
for (const auto& [typeId, typeName, baseClasses] : m_typeInfo)
|
||||
{
|
||||
if (AZStd::wildcard_match(searchTerm, typeName))
|
||||
{
|
||||
ComponentDetails details;
|
||||
details.m_typeInfo = AZStd::string::format("%s %s", typeId.ToString<AZStd::string>().c_str(), typeName.c_str());
|
||||
details.m_baseClasses = baseClasses;
|
||||
|
||||
matches.emplace_back(AZStd::move(details));
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
void EntityUtilityComponent::ResetEntityContext()
|
||||
{
|
||||
for (AZ::EntityId entityId : m_createdEntities)
|
||||
{
|
||||
m_entityContext->DestroyEntityById(entityId);
|
||||
}
|
||||
|
||||
m_createdEntities.clear();
|
||||
m_entityContext->ResetContext();
|
||||
}
|
||||
|
||||
void EntityUtilityComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
ComponentDetails::Reflect(context);
|
||||
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<EntityUtilityComponent, AZ::Component>();
|
||||
}
|
||||
|
||||
if (auto* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->ConstantProperty("InvalidComponentId", BehaviorConstant(AZ::InvalidComponentId))
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Entity")
|
||||
->Attribute(AZ::Script::Attributes::Module, "entity");
|
||||
|
||||
behaviorContext->EBus<EntityUtilityBus>("EntityUtilityBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Entity")
|
||||
->Attribute(AZ::Script::Attributes::Module, "entity")
|
||||
->Event("CreateEditorReadyEntity", &EntityUtilityBus::Events::CreateEditorReadyEntity)
|
||||
->Event("GetOrAddComponentByTypeName", &EntityUtilityBus::Events::GetOrAddComponentByTypeName)
|
||||
->Event("UpdateComponentForEntity", &EntityUtilityBus::Events::UpdateComponentForEntity)
|
||||
->Event("FindMatchingComponents", &EntityUtilityBus::Events::FindMatchingComponents)
|
||||
->Event("GetComponentDefaultJson", &EntityUtilityBus::Events::GetComponentDefaultJson)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityUtilityComponent::Activate()
|
||||
{
|
||||
m_entityContext = AZStd::make_unique<AzFramework::EntityContext>(UtilityEntityContextId);
|
||||
m_entityContext->InitContext();
|
||||
EntityUtilityBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void EntityUtilityComponent::Deactivate()
|
||||
{
|
||||
EntityUtilityBus::Handler::BusDisconnect();
|
||||
m_entityContext = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorDisabledCompositionBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorPendingCompositionBus.h>
|
||||
#include <AzToolsFramework/API/EntityCompositionRequestBus.h>
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzFramework/Entity/BehaviorEntity.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
struct ComponentDetails
|
||||
{
|
||||
AZ_TYPE_INFO(AzToolsFramework::ComponentDetails, "{107D8379-4AD4-4547-BEE1-184B120F23E9}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_typeInfo;
|
||||
AZStd::vector<AZStd::string> m_baseClasses;
|
||||
};
|
||||
|
||||
// This ebus is intended to provide behavior-context friendly APIs to create and manage entities
|
||||
struct EntityUtilityTraits : AZ::EBusTraits
|
||||
{
|
||||
AZ_RTTI(AzToolsFramework::EntityUtilityTraits, "{A6305CAE-C825-43F9-A44D-E503910912AF}");
|
||||
|
||||
virtual ~EntityUtilityTraits() = default;
|
||||
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
// Creates an entity with the default editor components attached and initializes the entity
|
||||
virtual AZ::EntityId CreateEditorReadyEntity(const AZStd::string& entityName) = 0;
|
||||
|
||||
virtual AzFramework::BehaviorComponentId GetOrAddComponentByTypeName(AZ::EntityId entity, const AZStd::string& typeName) = 0;
|
||||
|
||||
virtual bool UpdateComponentForEntity(AZ::EntityId entity, AzFramework::BehaviorComponentId component, const AZStd::string& json) = 0;
|
||||
|
||||
// Gets a JSON string containing describing the default serialization state of the specified component
|
||||
virtual AZStd::string GetComponentDefaultJson(const AZStd::string& typeName) = 0;
|
||||
|
||||
// Returns a list of matching component type names. Supports wildcard search terms
|
||||
virtual AZStd::vector<ComponentDetails> FindMatchingComponents(const AZStd::string& searchTerm) = 0;
|
||||
|
||||
virtual void ResetEntityContext() = 0;
|
||||
};
|
||||
|
||||
using EntityUtilityBus = AZ::EBus<EntityUtilityTraits>;
|
||||
|
||||
struct EntityUtilityComponent : AZ::Component
|
||||
, EntityUtilityBus::Handler
|
||||
{
|
||||
inline const static AZ::Uuid UtilityEntityContextId = AZ::Uuid("{9C277B88-E79E-4F8A-BAFF-A4C175BD565F}");
|
||||
|
||||
AZ_COMPONENT(EntityUtilityComponent, "{47205907-A0EA-4FFF-A620-04D20C04A379}");
|
||||
|
||||
AZ::EntityId CreateEditorReadyEntity(const AZStd::string& entityName) override;
|
||||
AzFramework::BehaviorComponentId GetOrAddComponentByTypeName(AZ::EntityId entity, const AZStd::string& typeName) override;
|
||||
bool UpdateComponentForEntity(AZ::EntityId entity, AzFramework::BehaviorComponentId component, const AZStd::string& json) override;
|
||||
AZStd::string GetComponentDefaultJson(const AZStd::string& typeName) override;
|
||||
AZStd::vector<ComponentDetails> FindMatchingComponents(const AZStd::string& searchTerm) override;
|
||||
void ResetEntityContext() override;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
protected:
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
// Our own entity context. This API is intended mostly for use in Asset Builders where there is no editor context
|
||||
// Additionally, an entity context is needed when using the Behavior Entity class
|
||||
AZStd::unique_ptr<AzFramework::EntityContext> m_entityContext;
|
||||
|
||||
// TypeId, TypeName, Vector<BaseClassName>
|
||||
AZStd::vector<AZStd::tuple<AZ::TypeId, AZStd::string, AZStd::vector<AZStd::string>>> m_typeInfo;
|
||||
|
||||
// Keep track of the entities we create so they can be reset
|
||||
AZStd::vector<AZ::EntityId> m_createdEntities;
|
||||
};
|
||||
}; // namespace AzToolsFramework
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
#include <AzFramework/Entity/EntityContextBus.h>
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerInterface.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeNotificationBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeSystemComponent.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerInterface.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -79,11 +79,11 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (!m_focusRoot.IsValid() && entityId.IsValid())
|
||||
{
|
||||
tracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Focus);
|
||||
tracker->ActivateMode({ GetEntityContextId() }, ViewportEditorMode::Focus);
|
||||
}
|
||||
else if (m_focusRoot.IsValid() && !entityId.IsValid())
|
||||
{
|
||||
tracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Focus);
|
||||
tracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Focus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -261,10 +261,10 @@ namespace AzToolsFramework
|
||||
// ensures cursor positions are refreshed correctly with context menu focus changes)
|
||||
if (eventType == QEvent::FocusIn)
|
||||
{
|
||||
const auto widgetCursorPosition = m_sourceWidget->mapFromGlobal(QCursor::pos());
|
||||
if (m_sourceWidget->geometry().contains(widgetCursorPosition))
|
||||
const auto globalCursorPosition = QCursor::pos();
|
||||
if (m_sourceWidget->geometry().contains(globalCursorPosition))
|
||||
{
|
||||
HandleMouseMoveEvent(widgetCursorPosition);
|
||||
HandleMouseMoveEvent(globalCursorPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,7 +290,7 @@ namespace AzToolsFramework
|
||||
else if (eventType == QEvent::Type::MouseMove)
|
||||
{
|
||||
auto mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
HandleMouseMoveEvent(mouseEvent->pos());
|
||||
HandleMouseMoveEvent(mouseEvent->globalPos());
|
||||
}
|
||||
// Map wheel events to the mouse Z movement channel.
|
||||
else if (eventType == QEvent::Type::Wheel)
|
||||
@@ -370,11 +370,12 @@ namespace AzToolsFramework
|
||||
return QPoint{ denormalizedX, denormalizedY };
|
||||
}
|
||||
|
||||
void QtEventToAzInputMapper::HandleMouseMoveEvent(const QPoint& cursorPosition)
|
||||
void QtEventToAzInputMapper::HandleMouseMoveEvent(const QPoint& globalCursorPosition)
|
||||
{
|
||||
const QPoint cursorDelta = cursorPosition - m_previousCursorPosition;
|
||||
const QPoint cursorDelta = globalCursorPosition - m_previousGlobalCursorPosition;
|
||||
|
||||
m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = WidgetPositionToNormalizedPosition(cursorPosition);
|
||||
m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition =
|
||||
WidgetPositionToNormalizedPosition(m_sourceWidget->mapFromGlobal(globalCursorPosition));
|
||||
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta = WidgetPositionToNormalizedPosition(cursorDelta);
|
||||
|
||||
ProcessPendingMouseEvents(cursorDelta);
|
||||
@@ -382,12 +383,11 @@ namespace AzToolsFramework
|
||||
if (m_capturingCursor)
|
||||
{
|
||||
// Reset our cursor position to the previous point
|
||||
const QPoint screenCursorPosition = m_sourceWidget->mapToGlobal(m_previousCursorPosition);
|
||||
AzQtComponents::SetCursorPos(screenCursorPosition);
|
||||
AzQtComponents::SetCursorPos(m_previousGlobalCursorPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_previousCursorPosition = cursorPosition;
|
||||
m_previousGlobalCursorPosition = globalCursorPosition;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace AzToolsFramework
|
||||
// Handle mouse click events.
|
||||
void HandleMouseButtonEvent(QMouseEvent* mouseEvent);
|
||||
// Handle mouse move events.
|
||||
void HandleMouseMoveEvent(const QPoint& cursorPosition);
|
||||
void HandleMouseMoveEvent(const QPoint& globalCursorPosition);
|
||||
// Handles key press / release events (or ShortcutOverride events for keys listed in m_highPriorityKeys).
|
||||
void HandleKeyEvent(QKeyEvent* keyEvent);
|
||||
// Handles mouse wheel events.
|
||||
@@ -156,8 +156,8 @@ namespace AzToolsFramework
|
||||
AZStd::unordered_set<Qt::Key> m_highPriorityKeys;
|
||||
// A lookup table for AZ input channel ID -> physical input channel on our mouse or keyboard device.
|
||||
AZStd::unordered_map<AzFramework::InputChannelId, AzFramework::InputChannel*> m_channels;
|
||||
// Where the position of the mouse cursor was at the last cursor event.
|
||||
QPoint m_previousCursorPosition;
|
||||
// Where the mouse cursor was at the last cursor event.
|
||||
QPoint m_previousGlobalCursorPosition;
|
||||
// The source widget to map events from, used to calculate the relative mouse position within the widget bounds.
|
||||
QWidget* m_sourceWidget;
|
||||
// Flags whether or not Qt events should currently be processed.
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace AzToolsFramework
|
||||
StringFunc::Path::Join(resolveBuffer, "log", logDirectory);
|
||||
fileIO->SetAlias("@log@", logDirectory.c_str());
|
||||
|
||||
fileIO->CreatePath("@root@");
|
||||
fileIO->CreatePath("@products@");
|
||||
fileIO->CreatePath("@user@");
|
||||
fileIO->CreatePath("@log@");
|
||||
|
||||
|
||||
@@ -224,6 +224,7 @@ namespace AzToolsFramework
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::Data::SerializedAssetTracker* assetTracker = settings.m_metadata.Find<AZ::Data::SerializedAssetTracker>();
|
||||
|
||||
referencedAssets = AZStd::move(assetTracker->GetTrackedAssets());
|
||||
@@ -245,6 +246,30 @@ namespace AzToolsFramework
|
||||
entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
|
||||
}
|
||||
|
||||
// some assets may come in from the JSON serialzier with no AssetID, but have an asset hint
|
||||
// this attempts to fix up the assets using the assetHint field
|
||||
auto fixUpInvalidAssets = [](AZ::Data::Asset<AZ::Data::AssetData>& asset)
|
||||
{
|
||||
if (!asset.GetId().IsValid() && !asset.GetHint().empty())
|
||||
{
|
||||
AZ::Data::AssetId assetId;
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
assetId,
|
||||
&AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
|
||||
asset.GetHint().c_str(),
|
||||
AZ::Data::s_invalidAssetType,
|
||||
false);
|
||||
|
||||
if (assetId.IsValid())
|
||||
{
|
||||
asset.Create(assetId, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto tracker = AZ::Data::SerializedAssetTracker{};
|
||||
tracker.SetAssetFixUp(fixUpInvalidAssets);
|
||||
|
||||
AZ::JsonDeserializerSettings settings;
|
||||
// The InstanceEntityIdMapper is registered twice because it's used in several places during deserialization where one is
|
||||
// specific for the InstanceEntityIdMapper and once for the generic JsonEntityIdMapper. Because the Json Serializer's meta
|
||||
@@ -252,16 +277,17 @@ namespace AzToolsFramework
|
||||
settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
|
||||
settings.m_metadata.Add(&entityIdMapper);
|
||||
settings.m_metadata.Create<InstanceEntityScrubber>(newlyAddedEntities);
|
||||
settings.m_metadata.Add(tracker);
|
||||
|
||||
AZStd::string scratchBuffer;
|
||||
auto issueReportingCallback = [&scratchBuffer](
|
||||
AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
|
||||
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
|
||||
AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
|
||||
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
|
||||
{
|
||||
return Internal::JsonIssueReporter(scratchBuffer, message, result, path);
|
||||
};
|
||||
settings.m_reporting = AZStd::move(issueReportingCallback);
|
||||
|
||||
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(instance, prefabDom, settings);
|
||||
|
||||
AZ::Data::AssetManager::Instance().ResumeAssetRelease();
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusHandler.h>
|
||||
|
||||
#include <AzToolsFramework/Commands/SelectionCommand.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusNotificationBus.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusUndo.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
@@ -27,15 +30,79 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
EditorEntityContextNotificationBus::Handler::BusConnect();
|
||||
AZ::Interface<PrefabFocusInterface>::Register(this);
|
||||
AZ::Interface<PrefabFocusPublicInterface>::Register(this);
|
||||
}
|
||||
|
||||
PrefabFocusHandler::~PrefabFocusHandler()
|
||||
{
|
||||
AZ::Interface<PrefabFocusPublicInterface>::Unregister(this);
|
||||
AZ::Interface<PrefabFocusInterface>::Unregister(this);
|
||||
EditorEntityContextNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::Initialize()
|
||||
{
|
||||
m_containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
|
||||
AZ_Assert(
|
||||
m_containerEntityInterface,
|
||||
"Prefab - PrefabFocusHandler - "
|
||||
"Container Entity Interface could not be found. "
|
||||
"Check that it is being correctly initialized.");
|
||||
|
||||
m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
AZ_Assert(
|
||||
m_focusModeInterface,
|
||||
"Prefab - PrefabFocusHandler - "
|
||||
"Focus Mode Interface could not be found. "
|
||||
"Check that it is being correctly initialized.");
|
||||
|
||||
m_instanceEntityMapperInterface = AZ::Interface<InstanceEntityMapperInterface>::Get();
|
||||
AZ_Assert(
|
||||
m_instanceEntityMapperInterface,
|
||||
"Prefab - PrefabFocusHandler - "
|
||||
"Instance Entity Mapper Interface could not be found. "
|
||||
"Check that it is being correctly initialized.");
|
||||
}
|
||||
|
||||
PrefabFocusOperationResult PrefabFocusHandler::FocusOnOwningPrefab(AZ::EntityId entityId)
|
||||
{
|
||||
// Initialize Undo Batch object
|
||||
ScopedUndoBatch undoBatch("Edit Prefab");
|
||||
|
||||
// Clear selection
|
||||
{
|
||||
const EntityIdList selectedEntities = EntityIdList{};
|
||||
auto selectionUndo = aznew SelectionCommand(selectedEntities, "Clear Selection");
|
||||
selectionUndo->SetParent(undoBatch.GetUndoBatch());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, selectedEntities);
|
||||
}
|
||||
|
||||
// Edit Prefab
|
||||
{
|
||||
auto editUndo = aznew PrefabFocusUndo("Edit Prefab");
|
||||
editUndo->Capture(entityId);
|
||||
editUndo->SetParent(undoBatch.GetUndoBatch());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, editUndo);
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex([[maybe_unused]] AzFramework::EntityContextId entityContextId, int index)
|
||||
{
|
||||
if (index < 0 || index >= m_instanceFocusVector.size())
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Prefab Focus Handler: Invalid index on FocusOnPathIndex."));
|
||||
}
|
||||
|
||||
InstanceOptionalReference focusedInstance = m_instanceFocusVector[index];
|
||||
|
||||
FocusOnOwningPrefab(focusedInstance->get().GetContainerEntityId());
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
PrefabFocusOperationResult PrefabFocusHandler::FocusOnPrefabInstanceOwningEntityId(AZ::EntityId entityId)
|
||||
{
|
||||
InstanceOptionalReference focusedInstance;
|
||||
|
||||
@@ -44,7 +111,7 @@ namespace AzToolsFramework::Prefab
|
||||
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
|
||||
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
|
||||
|
||||
if(!prefabEditorEntityOwnershipInterface)
|
||||
if (!prefabEditorEntityOwnershipInterface)
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Could not focus on root prefab instance - internal error "
|
||||
"(PrefabEditorEntityOwnershipInterface unavailable)."));
|
||||
@@ -60,18 +127,6 @@ namespace AzToolsFramework::Prefab
|
||||
return FocusOnPrefabInstance(focusedInstance);
|
||||
}
|
||||
|
||||
PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex([[maybe_unused]] AzFramework::EntityContextId entityContextId, int index)
|
||||
{
|
||||
if (index < 0 || index >= m_instanceFocusVector.size())
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Prefab Focus Handler: Invalid index on FocusOnPathIndex."));
|
||||
}
|
||||
|
||||
InstanceOptionalReference focusedInstance = m_instanceFocusVector[index];
|
||||
|
||||
return FocusOnPrefabInstance(focusedInstance);
|
||||
}
|
||||
|
||||
PrefabFocusOperationResult PrefabFocusHandler::FocusOnPrefabInstance(InstanceOptionalReference focusedInstance)
|
||||
{
|
||||
if (!focusedInstance.has_value())
|
||||
@@ -79,8 +134,16 @@ namespace AzToolsFramework::Prefab
|
||||
return AZ::Failure(AZStd::string("Prefab Focus Handler: invalid instance to focus on."));
|
||||
}
|
||||
|
||||
if (!m_isInitialized)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
if (!m_focusedInstance.has_value() || &m_focusedInstance->get() != &focusedInstance->get())
|
||||
{
|
||||
// Close all container entities in the old path
|
||||
CloseInstanceContainers(m_instanceFocusVector);
|
||||
|
||||
m_focusedInstance = focusedInstance;
|
||||
m_focusedTemplateId = focusedInstance->get().GetTemplateId();
|
||||
|
||||
@@ -89,26 +152,21 @@ namespace AzToolsFramework::Prefab
|
||||
if (focusedInstance->get().GetParentInstance() != AZStd::nullopt)
|
||||
{
|
||||
containerEntityId = focusedInstance->get().GetContainerEntityId();
|
||||
|
||||
// Select the container entity
|
||||
AzToolsFramework::SelectEntity(containerEntityId);
|
||||
}
|
||||
else
|
||||
{
|
||||
containerEntityId = AZ::EntityId();
|
||||
|
||||
// Clear the selection
|
||||
AzToolsFramework::SelectEntities({});
|
||||
|
||||
}
|
||||
|
||||
// Focus on the descendants of the container entity
|
||||
if (FocusModeInterface* focusModeInterface = AZ::Interface<FocusModeInterface>::Get())
|
||||
{
|
||||
focusModeInterface->SetFocusRoot(containerEntityId);
|
||||
}
|
||||
m_focusModeInterface->SetFocusRoot(containerEntityId);
|
||||
|
||||
// Refresh path variables
|
||||
RefreshInstanceFocusList();
|
||||
|
||||
// Open all container entities in the new path
|
||||
OpenInstanceContainers(m_instanceFocusVector);
|
||||
|
||||
PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged);
|
||||
}
|
||||
|
||||
@@ -126,6 +184,17 @@ namespace AzToolsFramework::Prefab
|
||||
return m_focusedInstance;
|
||||
}
|
||||
|
||||
AZ::EntityId PrefabFocusHandler::GetFocusedPrefabContainerEntityId([[maybe_unused]] AzFramework::EntityContextId entityContextId) const
|
||||
{
|
||||
if (!m_focusedInstance.has_value())
|
||||
{
|
||||
// PrefabFocusHandler has not been initialized yet.
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
return m_focusedInstance->get().GetContainerEntityId();
|
||||
}
|
||||
|
||||
bool PrefabFocusHandler::IsOwningPrefabBeingFocused(AZ::EntityId entityId) const
|
||||
{
|
||||
if (!m_focusedInstance.has_value())
|
||||
@@ -156,8 +225,16 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
void PrefabFocusHandler::OnEntityStreamLoadSuccess()
|
||||
{
|
||||
if (!m_isInitialized)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
// Clear the old focus vector
|
||||
m_instanceFocusVector.clear();
|
||||
|
||||
// Focus on the root prefab (AZ::EntityId() will default to it)
|
||||
FocusOnOwningPrefab(AZ::EntityId());
|
||||
FocusOnPrefabInstanceOwningEntityId(AZ::EntityId());
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::RefreshInstanceFocusList()
|
||||
@@ -184,4 +261,26 @@ namespace AzToolsFramework::Prefab
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::OpenInstanceContainers(const AZStd::vector<InstanceOptionalReference>& instances) const
|
||||
{
|
||||
for (const InstanceOptionalReference& instance : instances)
|
||||
{
|
||||
if (instance.has_value())
|
||||
{
|
||||
m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::CloseInstanceContainers(const AZStd::vector<InstanceOptionalReference>& instances) const
|
||||
{
|
||||
for (const InstanceOptionalReference& instance : instances)
|
||||
{
|
||||
if (instance.has_value())
|
||||
{
|
||||
m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
|
||||
@@ -13,8 +13,15 @@
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Template/Template.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class ContainerEntityInterface;
|
||||
class FocusModeInterface;
|
||||
}
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
class InstanceEntityMapperInterface;
|
||||
@@ -22,6 +29,7 @@ namespace AzToolsFramework::Prefab
|
||||
//! Handles Prefab Focus mode, determining which prefab file entity changes will target.
|
||||
class PrefabFocusHandler final
|
||||
: private PrefabFocusInterface
|
||||
, private PrefabFocusPublicInterface
|
||||
, private EditorEntityContextNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
@@ -30,11 +38,17 @@ namespace AzToolsFramework::Prefab
|
||||
PrefabFocusHandler();
|
||||
~PrefabFocusHandler();
|
||||
|
||||
void Initialize();
|
||||
|
||||
// PrefabFocusInterface overrides ...
|
||||
PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override;
|
||||
PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) override;
|
||||
PrefabFocusOperationResult FocusOnPrefabInstanceOwningEntityId(AZ::EntityId entityId) override;
|
||||
TemplateId GetFocusedPrefabTemplateId(AzFramework::EntityContextId entityContextId) const override;
|
||||
InstanceOptionalReference GetFocusedPrefabInstance(AzFramework::EntityContextId entityContextId) const override;
|
||||
|
||||
// PrefabFocusPublicInterface overrides ...
|
||||
PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override;
|
||||
PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) override;
|
||||
AZ::EntityId GetFocusedPrefabContainerEntityId(AzFramework::EntityContextId entityContextId) const override;
|
||||
bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const override;
|
||||
const AZ::IO::Path& GetPrefabFocusPath(AzFramework::EntityContextId entityContextId) const override;
|
||||
const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const override;
|
||||
@@ -46,12 +60,19 @@ namespace AzToolsFramework::Prefab
|
||||
PrefabFocusOperationResult FocusOnPrefabInstance(InstanceOptionalReference focusedInstance);
|
||||
void RefreshInstanceFocusList();
|
||||
|
||||
void OpenInstanceContainers(const AZStd::vector<InstanceOptionalReference>& instances) const;
|
||||
void CloseInstanceContainers(const AZStd::vector<InstanceOptionalReference>& instances) const;
|
||||
|
||||
InstanceOptionalReference m_focusedInstance;
|
||||
TemplateId m_focusedTemplateId;
|
||||
AZStd::vector<InstanceOptionalReference> m_instanceFocusVector;
|
||||
AZ::IO::Path m_instanceFocusPath;
|
||||
|
||||
InstanceEntityMapperInterface* m_instanceEntityMapperInterface;
|
||||
ContainerEntityInterface* m_containerEntityInterface = nullptr;
|
||||
FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr;
|
||||
|
||||
bool m_isInitialized = false;
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace AzToolsFramework::Prefab
|
||||
{
|
||||
using PrefabFocusOperationResult = AZ::Outcome<void, AZStd::string>;
|
||||
|
||||
//! Interface to handle operations related to the Prefab Focus system.
|
||||
//! Interface to handle internal operations related to the Prefab Focus system.
|
||||
class PrefabFocusInterface
|
||||
{
|
||||
public:
|
||||
@@ -28,29 +28,13 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
//! Set the focused prefab instance to the owning instance of the entityId provided.
|
||||
//! @param entityId The entityId of the entity whose owning instance we want the prefab system to focus on.
|
||||
virtual PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) = 0;
|
||||
|
||||
//! Set the focused prefab instance to the instance at position index of the current path.
|
||||
//! @param index The index of the instance in the current path that we want the prefab system to focus on.
|
||||
virtual PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) = 0;
|
||||
virtual PrefabFocusOperationResult FocusOnPrefabInstanceOwningEntityId(AZ::EntityId entityId) = 0;
|
||||
|
||||
//! Returns the template id of the instance the prefab system is focusing on.
|
||||
virtual TemplateId GetFocusedPrefabTemplateId(AzFramework::EntityContextId entityContextId) const = 0;
|
||||
|
||||
//! Returns a reference to the instance the prefab system is focusing on.
|
||||
virtual InstanceOptionalReference GetFocusedPrefabInstance(AzFramework::EntityContextId entityContextId) const = 0;
|
||||
|
||||
//! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants.
|
||||
//! @param entityId The entityId of the queried entity.
|
||||
//! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise.
|
||||
virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const = 0;
|
||||
|
||||
//! Returns the path from the root instance to the currently focused instance.
|
||||
//! @return A path composed from the names of the container entities for the instance path.
|
||||
virtual const AZ::IO::Path& GetPrefabFocusPath(AzFramework::EntityContextId entityContextId) const = 0;
|
||||
|
||||
//! Returns the size of the path to the currently focused instance.
|
||||
virtual const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const = 0;
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
#include <AzFramework/Entity/EntityContext.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Template/Template.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
using PrefabFocusOperationResult = AZ::Outcome<void, AZStd::string>;
|
||||
|
||||
//! Public Interface for external systems to utilize the Prefab Focus system.
|
||||
class PrefabFocusPublicInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PrefabFocusPublicInterface, "{53EE1D18-A41F-4DB1-9B73-9448F425722E}");
|
||||
|
||||
//! Set the focused prefab instance to the owning instance of the entityId provided. Supports undo/redo.
|
||||
//! @param entityId The entityId of the entity whose owning instance we want the prefab system to focus on.
|
||||
virtual PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) = 0;
|
||||
|
||||
//! Set the focused prefab instance to the instance at position index of the current path. Supports undo/redo.
|
||||
//! @param index The index of the instance in the current path that we want the prefab system to focus on.
|
||||
virtual PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) = 0;
|
||||
|
||||
//! Returns the entity id of the container entity for the instance the prefab system is focusing on.
|
||||
virtual AZ::EntityId GetFocusedPrefabContainerEntityId(AzFramework::EntityContextId entityContextId) const = 0;
|
||||
|
||||
//! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants.
|
||||
//! @param entityId The entityId of the queried entity.
|
||||
//! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise.
|
||||
virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const = 0;
|
||||
|
||||
//! Returns the path from the root instance to the currently focused instance.
|
||||
//! @return A path composed from the names of the container entities for the instance path.
|
||||
virtual const AZ::IO::Path& GetPrefabFocusPath(AzFramework::EntityContextId entityContextId) const = 0;
|
||||
|
||||
//! Returns the size of the path to the currently focused instance.
|
||||
virtual const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const = 0;
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusUndo.h>
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
PrefabFocusUndo::PrefabFocusUndo(const AZStd::string& undoOperationName)
|
||||
: UndoSystem::URSequencePoint(undoOperationName)
|
||||
{
|
||||
m_prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
|
||||
AZ_Assert(m_prefabFocusInterface, "PrefabFocusUndo - Failed to grab prefab focus interface");
|
||||
|
||||
m_prefabFocusPublicInterface = AZ::Interface<PrefabFocusPublicInterface>::Get();
|
||||
AZ_Assert(m_prefabFocusPublicInterface, "PrefabFocusUndo - Failed to grab prefab focus public interface");
|
||||
}
|
||||
|
||||
bool PrefabFocusUndo::Changed() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrefabFocusUndo::Capture(AZ::EntityId entityId)
|
||||
{
|
||||
auto entityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(entityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
m_beforeEntityId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(entityContextId);
|
||||
m_afterEntityId = entityId;
|
||||
}
|
||||
|
||||
void PrefabFocusUndo::Undo()
|
||||
{
|
||||
m_prefabFocusInterface->FocusOnPrefabInstanceOwningEntityId(m_beforeEntityId);
|
||||
}
|
||||
|
||||
void PrefabFocusUndo::Redo()
|
||||
{
|
||||
m_prefabFocusInterface->FocusOnPrefabInstanceOwningEntityId(m_afterEntityId);
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzToolsFramework/Undo/UndoSystem.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
class PrefabFocusInterface;
|
||||
class PrefabFocusPublicInterface;
|
||||
|
||||
//! Undo node for prefab focus change operations.
|
||||
class PrefabFocusUndo
|
||||
: public UndoSystem::URSequencePoint
|
||||
{
|
||||
public:
|
||||
explicit PrefabFocusUndo(const AZStd::string& undoOperationName);
|
||||
|
||||
bool Changed() const override;
|
||||
void Capture(AZ::EntityId entityId);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
protected:
|
||||
PrefabFocusInterface* m_prefabFocusInterface = nullptr;
|
||||
PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr;
|
||||
|
||||
AZ::EntityId m_beforeEntityId;
|
||||
AZ::EntityId m_afterEntityId;
|
||||
};
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
@@ -50,17 +50,19 @@ namespace AzToolsFramework
|
||||
|
||||
auto settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
AZ_Assert(settingsRegistry, "Settings registry is not set");
|
||||
|
||||
|
||||
[[maybe_unused]] bool result =
|
||||
settingsRegistry->Get(m_projectPathWithOsSeparator.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath);
|
||||
AZ_Warning("Prefab", result, "Couldn't retrieve project root path");
|
||||
m_projectPathWithSlashSeparator = AZ::IO::Path(m_projectPathWithOsSeparator.Native(), '/').MakePreferred();
|
||||
|
||||
AZ::Interface<PrefabLoaderInterface>::Register(this);
|
||||
m_scriptingPrefabLoader.Connect(this);
|
||||
}
|
||||
|
||||
void PrefabLoader::UnregisterPrefabLoaderInterface()
|
||||
{
|
||||
m_scriptingPrefabLoader.Disconnect();
|
||||
AZ::Interface<PrefabLoaderInterface>::Unregister(this);
|
||||
}
|
||||
|
||||
@@ -568,7 +570,7 @@ namespace AzToolsFramework
|
||||
(pathStr.find_first_of(AZ_FILESYSTEM_INVALID_CHARACTERS) == AZStd::string::npos) &&
|
||||
(pathStr.back() != '\\' && pathStr.back() != '/');
|
||||
}
|
||||
|
||||
|
||||
AZ::IO::Path PrefabLoader::GetFullPath(AZ::IO::PathView path)
|
||||
{
|
||||
AZ::IO::Path pathWithOSSeparator = AZ::IO::Path(path).MakePreferred();
|
||||
@@ -596,26 +598,38 @@ namespace AzToolsFramework
|
||||
{
|
||||
// The asset system provided us with a valid root folder and relative path, so return it.
|
||||
fullPath = AZ::IO::Path(rootFolder) / assetInfo.m_relativePath;
|
||||
return fullPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If for some reason the Asset system couldn't provide a relative path, provide some fallback logic.
|
||||
|
||||
// Check to see if the AssetProcessor is ready. If it *is* and we didn't get a path, print an error then follow
|
||||
// the fallback logic. If it's *not* ready, we're probably either extremely early in a tool startup flow or inside
|
||||
// a unit test, so just execute the fallback logic without an error.
|
||||
[[maybe_unused]] bool assetProcessorReady = false;
|
||||
AzFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
assetProcessorReady, &AzFramework::AssetSystemRequestBus::Events::AssetProcessorIsReady);
|
||||
|
||||
AZ_Error(
|
||||
"Prefab", !assetProcessorReady, "Full source path for '%.*s' could not be determined. Using fallback logic.",
|
||||
AZ_STRING_ARG(path.Native()));
|
||||
|
||||
// If a relative path was passed in, make it relative to the project root.
|
||||
fullPath = AZ::IO::Path(m_projectPathWithOsSeparator).Append(pathWithOSSeparator);
|
||||
// attempt to find the absolute from the Cache folder
|
||||
AZStd::string assetRootFolder;
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
settingsRegistry->Get(assetRootFolder, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder);
|
||||
}
|
||||
fullPath = AZ::IO::Path(assetRootFolder) / path;
|
||||
if (fullPath.IsAbsolute() && AZ::IO::SystemFile::Exists(fullPath.c_str()))
|
||||
{
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
|
||||
// If for some reason the Asset system couldn't provide a relative path, provide some fallback logic.
|
||||
|
||||
// Check to see if the AssetProcessor is ready. If it *is* and we didn't get a path, print an error then follow
|
||||
// the fallback logic. If it's *not* ready, we're probably either extremely early in a tool startup flow or inside
|
||||
// a unit test, so just execute the fallback logic without an error.
|
||||
[[maybe_unused]] bool assetProcessorReady = false;
|
||||
AzFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
assetProcessorReady, &AzFramework::AssetSystemRequestBus::Events::AssetProcessorIsReady);
|
||||
|
||||
AZ_Error(
|
||||
"Prefab", !assetProcessorReady, "Full source path for '%.*s' could not be determined. Using fallback logic.",
|
||||
AZ_STRING_ARG(path.Native()));
|
||||
|
||||
// If a relative path was passed in, make it relative to the project root.
|
||||
fullPath = AZ::IO::Path(m_projectPathWithOsSeparator).Append(pathWithOSSeparator);
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomTypes.h>
|
||||
#include <Prefab/ScriptingPrefabLoader.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -114,6 +115,7 @@ namespace AzToolsFramework
|
||||
void SetSaveAllPrefabsPreference(SaveAllPrefabsPreference saveAllPrefabsPreference) override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Copies the template dom provided and manipulates it into the proper format to be saved to disk.
|
||||
* @param templateRef The template whose dom we want to transform into the proper format to be saved to disk.
|
||||
@@ -177,6 +179,7 @@ namespace AzToolsFramework
|
||||
AZStd::optional<AZStd::pair<PrefabDom, AZ::IO::Path>> StoreTemplateIntoFileFormat(TemplateId templateId);
|
||||
|
||||
PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr;
|
||||
ScriptingPrefabLoader m_scriptingPrefabLoader;
|
||||
AZ::IO::Path m_projectPathWithOsSeparator;
|
||||
AZ::IO::Path m_projectPathWithSlashSeparator;
|
||||
};
|
||||
|
||||
@@ -99,7 +99,6 @@ namespace AzToolsFramework
|
||||
// Generates a new path
|
||||
static AZ::IO::Path GeneratePath();
|
||||
};
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
// Ebus for script-friendly APIs for the prefab loader
|
||||
struct PrefabLoaderScriptingTraits : AZ::EBusTraits
|
||||
{
|
||||
AZ_TYPE_INFO(PrefabLoaderScriptingTraits, "{C344B7D8-8299-48C9-8450-26E1332EA011}");
|
||||
|
||||
virtual ~PrefabLoaderScriptingTraits() = default;
|
||||
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
/**
|
||||
* Saves a Prefab Template into the provided output string.
|
||||
* Converts Prefab Template form into .prefab form by collapsing nested Template info
|
||||
* into a source path and patches.
|
||||
* @param templateId Id of the template to be saved
|
||||
* @return Will contain the serialized template json on success
|
||||
*/
|
||||
virtual AZ::Outcome<AZStd::string, void> SaveTemplateToString(TemplateId templateId) = 0;
|
||||
};
|
||||
|
||||
using PrefabLoaderScriptingBus = AZ::EBus<PrefabLoaderScriptingTraits>;
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -257,9 +257,10 @@ namespace AzToolsFramework
|
||||
|
||||
// Select Container Entity
|
||||
{
|
||||
auto selectionUndo = aznew SelectionCommand({ containerEntityId }, "Select Prefab Container Entity");
|
||||
const EntityIdList selectedEntities = EntityIdList{ containerEntityId };
|
||||
auto selectionUndo = aznew SelectionCommand(selectedEntities, "Select Prefab Container Entity");
|
||||
selectionUndo->SetParent(undoBatch.GetUndoBatch());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, selectionUndo);
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, selectedEntities);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1097,7 +1098,7 @@ namespace AzToolsFramework
|
||||
// Select the duplicated entities/instances
|
||||
auto selectionUndo = aznew SelectionCommand(duplicatedEntityAndInstanceIds, "Select Duplicated Entities/Instances");
|
||||
selectionUndo->SetParent(undoBatch.GetUndoBatch());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, selectionUndo);
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, duplicatedEntityAndInstanceIds);
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.h>
|
||||
@@ -36,12 +37,14 @@ namespace AzToolsFramework
|
||||
m_instanceToTemplatePropagator.RegisterInstanceToTemplateInterface();
|
||||
m_prefabPublicHandler.RegisterPrefabPublicHandlerInterface();
|
||||
m_prefabPublicRequestHandler.Connect();
|
||||
m_prefabSystemScriptingHandler.Connect(this);
|
||||
AZ::SystemTickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void PrefabSystemComponent::Deactivate()
|
||||
{
|
||||
AZ::SystemTickBus::Handler::BusDisconnect();
|
||||
m_prefabSystemScriptingHandler.Disconnect();
|
||||
m_prefabPublicRequestHandler.Disconnect();
|
||||
m_prefabPublicHandler.UnregisterPrefabPublicHandlerInterface();
|
||||
m_instanceToTemplatePropagator.UnregisterInstanceToTemplateInterface();
|
||||
@@ -58,13 +61,24 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover::Reflect(context);
|
||||
PrefabPublicRequestHandler::Reflect(context);
|
||||
PrefabLoader::Reflect(context);
|
||||
PrefabSystemScriptingHandler::Reflect(context);
|
||||
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<PrefabSystemComponent, AZ::Component>()->Version(1);
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
|
||||
behaviorContext->EBus<PrefabLoaderScriptingBus>("PrefabLoaderScriptingBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "prefab")
|
||||
->Attribute(AZ::Script::Attributes::Category, "Prefab")
|
||||
->Event("SaveTemplateToString", &PrefabLoaderScriptingBus::Events::SaveTemplateToString);
|
||||
;
|
||||
}
|
||||
|
||||
AZ::JsonRegistrationContext* jsonRegistration = azrtti_cast<AZ::JsonRegistrationContext*>(context);
|
||||
if (jsonRegistration)
|
||||
{
|
||||
@@ -145,7 +159,7 @@ namespace AzToolsFramework
|
||||
newInstance->SetTemplateId(newTemplateId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId, bool immediate, InstanceOptionalReference instanceToExclude)
|
||||
{
|
||||
UpdatePrefabInstances(templateId, immediate, instanceToExclude);
|
||||
@@ -927,7 +941,7 @@ namespace AzToolsFramework
|
||||
|
||||
PrefabDomValue& instance = instanceIterator->value;
|
||||
AZ_Assert(instance.IsObject(), "Nested instance DOM provided is not a valid JSON object.");
|
||||
PrefabDomValueReference sourceTemplateName = PrefabDomUtils::FindPrefabDomValue(instance, PrefabDomUtils::SourceName);
|
||||
[[maybe_unused]] PrefabDomValueReference sourceTemplateName = PrefabDomUtils::FindPrefabDomValue(instance, PrefabDomUtils::SourceName);
|
||||
AZ_Assert(sourceTemplateName, "Couldn't find source template name in the DOM of the nested instance while creating a link.");
|
||||
AZ_Assert(sourceTemplateName->get() == sourceTemplate.GetFilePath().c_str(),
|
||||
"The name of the source template in the nested instance DOM does not match the name of the source template already loaded");
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicRequestHandler.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Template/Template.h>
|
||||
#include <Prefab/PrefabSystemScriptingHandler.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -219,7 +220,7 @@ namespace AzToolsFramework
|
||||
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Instance>>&& instancesToConsume,
|
||||
AZ::IO::PathView filePath, AZStd::unique_ptr<AZ::Entity> containerEntity = nullptr,
|
||||
InstanceOptionalReference parent = AZStd::nullopt, bool shouldCreateLinks = true) override;
|
||||
|
||||
|
||||
PrefabDom& FindTemplateDom(TemplateId templateId) override;
|
||||
|
||||
/**
|
||||
@@ -244,7 +245,7 @@ namespace AzToolsFramework
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(PrefabSystemComponent);
|
||||
|
||||
|
||||
/**
|
||||
* Builds a new Prefab Template out of entities and instances and returns the first instance comprised of
|
||||
* these entities and instances.
|
||||
@@ -412,6 +413,8 @@ namespace AzToolsFramework
|
||||
|
||||
// Handler of the public Prefab requests.
|
||||
PrefabPublicRequestHandler m_prefabPublicRequestHandler;
|
||||
|
||||
PrefabSystemScriptingHandler m_prefabSystemScriptingHandler;
|
||||
};
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+1
-2
@@ -78,8 +78,7 @@ namespace AzToolsFramework
|
||||
AZStd::unique_ptr<AZ::Entity> containerEntity = nullptr, InstanceOptionalReference parent = AZStd::nullopt,
|
||||
bool shouldCreateLinks = true) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Link/Link.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
#include <AzToolsFramework/Prefab/Template/Template.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
// Bus that exposes a script-friendly interface to the PrefabSystemComponent
|
||||
struct PrefabSystemScriptingEbusTraits : AZ::EBusTraits
|
||||
{
|
||||
using MutexType = AZ::NullMutex;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
|
||||
virtual TemplateId CreatePrefabTemplate(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, const AZStd::string& filePath) = 0;
|
||||
};
|
||||
|
||||
using PrefabSystemScriptingBus = AZ::EBus<PrefabSystemScriptingEbusTraits>;
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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/ComponentApplicationBus.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <Prefab/PrefabSystemScriptingHandler.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
void PrefabSystemScriptingHandler::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->ConstantProperty("InvalidTemplateId", BehaviorConstant(InvalidTemplateId))
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "prefab")
|
||||
->Attribute(AZ::Script::Attributes::Category, "Prefab");
|
||||
|
||||
behaviorContext->EBus<PrefabSystemScriptingBus>("PrefabSystemScriptingBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "prefab")
|
||||
->Attribute(AZ::Script::Attributes::Category, "Prefab")
|
||||
->Event("CreatePrefab", &PrefabSystemScriptingBus::Events::CreatePrefabTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabSystemScriptingHandler::Connect(PrefabSystemComponentInterface* prefabSystemComponentInterface)
|
||||
{
|
||||
AZ_Assert(prefabSystemComponentInterface != nullptr, "prefabSystemComponentInterface must not be null");
|
||||
m_prefabSystemComponentInterface = prefabSystemComponentInterface;
|
||||
PrefabSystemScriptingBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void PrefabSystemScriptingHandler::Disconnect()
|
||||
{
|
||||
PrefabSystemScriptingBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
TemplateId PrefabSystemScriptingHandler::CreatePrefabTemplate(const AZStd::vector<AZ::EntityId>& entityIds, const AZStd::string& filePath)
|
||||
{
|
||||
AZStd::vector<AZ::Entity*> entities;
|
||||
|
||||
for (const auto& entityId : entityIds)
|
||||
{
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, entityId);
|
||||
|
||||
AZ_Warning(
|
||||
"PrefabSystemComponent", entity, "EntityId %s was not found and will not be added to the prefab",
|
||||
entityId.ToString().c_str());
|
||||
|
||||
if (entity)
|
||||
{
|
||||
entities.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
auto prefab = m_prefabSystemComponentInterface->CreatePrefab(entities, {}, AZ::IO::PathView(AZStd::string_view(filePath)));
|
||||
|
||||
if (!prefab)
|
||||
{
|
||||
AZ_Error("PrefabSystemComponenent", false, "Failed to create prefab %s", filePath.c_str());
|
||||
return InvalidTemplateId;
|
||||
}
|
||||
|
||||
return prefab->GetTemplateId();
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <Prefab/PrefabSystemScriptingBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
class PrefabSystemScriptingHandler
|
||||
: PrefabSystemScriptingBus::Handler
|
||||
{
|
||||
public:
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
PrefabSystemScriptingHandler() = default;
|
||||
|
||||
void Connect(PrefabSystemComponentInterface* prefabSystemComponentInterface);
|
||||
void Disconnect();
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY(PrefabSystemScriptingHandler);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// PrefabSystemScriptingBus implementation
|
||||
TemplateId CreatePrefabTemplate(const AZStd::vector<AZ::EntityId>& entityIds, const AZStd::string& filePath) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr;
|
||||
};
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include <Prefab/Procedural/ProceduralPrefabAsset.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzFramework/FileFunc/FileFunc.h>
|
||||
|
||||
namespace AZ::Prefab
|
||||
{
|
||||
static constexpr const char s_useProceduralPrefabsKey[] = "/O3DE/Preferences/Prefabs/UseProceduralPrefabs";
|
||||
|
||||
// ProceduralPrefabAsset
|
||||
|
||||
ProceduralPrefabAsset::ProceduralPrefabAsset(const AZ::Data::AssetId& assetId)
|
||||
: AZ::Data::AssetData(assetId)
|
||||
, m_templateId(AzToolsFramework::Prefab::InvalidTemplateId)
|
||||
{
|
||||
}
|
||||
|
||||
void ProceduralPrefabAsset::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
PrefabDomData::Reflect(context);
|
||||
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
|
||||
{
|
||||
serializeContext->Class<ProceduralPrefabAsset, AZ::Data::AssetData>()
|
||||
->Version(1)
|
||||
->Field("Template Name", &ProceduralPrefabAsset::m_templateName)
|
||||
->Field("Template ID", &ProceduralPrefabAsset::m_templateId);
|
||||
}
|
||||
}
|
||||
|
||||
const AZStd::string& ProceduralPrefabAsset::GetTemplateName() const
|
||||
{
|
||||
return m_templateName;
|
||||
}
|
||||
|
||||
void ProceduralPrefabAsset::SetTemplateName(AZStd::string templateName)
|
||||
{
|
||||
m_templateName = AZStd::move(templateName);
|
||||
}
|
||||
|
||||
AzToolsFramework::Prefab::TemplateId ProceduralPrefabAsset::GetTemplateId() const
|
||||
{
|
||||
return m_templateId;
|
||||
}
|
||||
|
||||
void ProceduralPrefabAsset::SetTemplateId(AzToolsFramework::Prefab::TemplateId templateId)
|
||||
{
|
||||
m_templateId = templateId;
|
||||
}
|
||||
|
||||
bool ProceduralPrefabAsset::UseProceduralPrefabs()
|
||||
{
|
||||
bool useProceduralPrefabs = false;
|
||||
bool result = AZ::SettingsRegistry::Get()->GetObject(useProceduralPrefabs, s_useProceduralPrefabsKey);
|
||||
return result && useProceduralPrefabs;
|
||||
}
|
||||
|
||||
// PrefabDomData
|
||||
|
||||
void PrefabDomData::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* jsonContext = azrtti_cast<AZ::JsonRegistrationContext*>(context))
|
||||
{
|
||||
jsonContext->Serializer<PrefabDomDataJsonSerializer>()->HandlesType<PrefabDomData>();
|
||||
}
|
||||
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<PrefabDomData>()
|
||||
->Version(1);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabDomData::CopyValue(const rapidjson::Value& inputValue)
|
||||
{
|
||||
m_prefabDom.CopyFrom(inputValue, m_prefabDom.GetAllocator());
|
||||
}
|
||||
|
||||
const AzToolsFramework::Prefab::PrefabDom& PrefabDomData::GetValue() const
|
||||
{
|
||||
return m_prefabDom;
|
||||
}
|
||||
|
||||
// PrefabDomDataJsonSerializer
|
||||
|
||||
AZ::JsonSerializationResult::Result PrefabDomDataJsonSerializer::Load(
|
||||
void* outputValue,
|
||||
[[maybe_unused]] const AZ::Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue,
|
||||
AZ::JsonDeserializerContext& context)
|
||||
{
|
||||
AZ_Assert(outputValueTypeId == azrtti_typeid<PrefabDomData>(),
|
||||
"PrefabDomDataJsonSerializer Load against output typeID that was not PrefabDomData");
|
||||
AZ_Assert(outputValue, "PrefabDomDataJsonSerializer Load against null output");
|
||||
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
|
||||
if (inputValue.IsObject() == false)
|
||||
{
|
||||
result.Combine(context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Missing, "Missing object"));
|
||||
return context.Report(result, "Prefab should be an object.");
|
||||
}
|
||||
|
||||
if (inputValue.MemberCount() < 1)
|
||||
{
|
||||
result.Combine(context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Missing, "Missing members"));
|
||||
return context.Report(result, "Prefab should have multiple members.");
|
||||
}
|
||||
|
||||
auto* outputVariable = reinterpret_cast<PrefabDomData*>(outputValue);
|
||||
outputVariable->CopyValue(inputValue);
|
||||
return context.Report(result, "Loaded procedural prefab");
|
||||
}
|
||||
|
||||
AZ::JsonSerializationResult::Result PrefabDomDataJsonSerializer::Store(
|
||||
rapidjson::Value& outputValue,
|
||||
const void* inputValue,
|
||||
[[maybe_unused]] const void* defaultValue,
|
||||
[[maybe_unused]] const AZ::Uuid& valueTypeId,
|
||||
AZ::JsonSerializerContext& context)
|
||||
{
|
||||
AZ_Assert(inputValue, "Input value for PrefabDomDataJsonSerializer can't be null.");
|
||||
AZ_Assert(azrtti_typeid<PrefabDomData>() == valueTypeId,
|
||||
"Unable to Serialize because the provided type is not PrefabGroup::PrefabDomData.");
|
||||
|
||||
const PrefabDomData* prefabDomData = reinterpret_cast<const PrefabDomData*>(inputValue);
|
||||
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
JSR::ResultCode result(JSR::Tasks::WriteValue);
|
||||
outputValue.SetObject();
|
||||
outputValue.CopyFrom(prefabDomData->GetValue(), context.GetJsonAllocator());
|
||||
return context.Report(result, "Stored procedural prefab");
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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/Asset/AssetCommon.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomTypes.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||
|
||||
namespace AZ::Prefab
|
||||
{
|
||||
//! A wrapper around the JSON DOM type so that the assets can read in and write out
|
||||
//! JSON directly since Prefabs are JSON serialized entity-component data
|
||||
class PrefabDomData final
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PrefabDomData, "{C73A3360-D772-4D41-9118-A039BF9340C1}");
|
||||
AZ_CLASS_ALLOCATOR(PrefabDomData, AZ::SystemAllocator, 0);
|
||||
|
||||
PrefabDomData() = default;
|
||||
~PrefabDomData() = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
void CopyValue(const rapidjson::Value& inputValue);
|
||||
const AzToolsFramework::Prefab::PrefabDom& GetValue() const;
|
||||
|
||||
private:
|
||||
AzToolsFramework::Prefab::PrefabDom m_prefabDom;
|
||||
};
|
||||
|
||||
//! Registered to help read/write JSON for the PrefabDomData::m_prefabDom
|
||||
class PrefabDomDataJsonSerializer final
|
||||
: public AZ::BaseJsonSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PrefabDomDataJsonSerializer, "{9FC48652-A00B-4EFA-8FD9-345A8E625439}", BaseJsonSerializer);
|
||||
AZ_CLASS_ALLOCATOR(PrefabDomDataJsonSerializer, AZ::SystemAllocator, 0);
|
||||
|
||||
~PrefabDomDataJsonSerializer() override = default;
|
||||
|
||||
AZ::JsonSerializationResult::Result Load(
|
||||
void* outputValue,
|
||||
const AZ::Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue,
|
||||
AZ::JsonDeserializerContext& context) override;
|
||||
|
||||
AZ::JsonSerializationResult::Result Store(
|
||||
rapidjson::Value& outputValue,
|
||||
const void* inputValue,
|
||||
const void* defaultValue,
|
||||
const AZ::Uuid& valueTypeId,
|
||||
AZ::JsonSerializerContext& context) override;
|
||||
};
|
||||
|
||||
//! An asset type to register templates into the Prefab system so that they
|
||||
//! can instantiate like Authored Prefabs
|
||||
class ProceduralPrefabAsset
|
||||
: public AZ::Data::AssetData
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ProceduralPrefabAsset, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(ProceduralPrefabAsset, "{9B7C8459-471E-4EAD-A363-7990CC4065A9}", AZ::Data::AssetData);
|
||||
|
||||
static bool UseProceduralPrefabs();
|
||||
|
||||
ProceduralPrefabAsset(const AZ::Data::AssetId& assetId = AZ::Data::AssetId());
|
||||
~ProceduralPrefabAsset() override = default;
|
||||
ProceduralPrefabAsset(const ProceduralPrefabAsset& rhs) = delete;
|
||||
ProceduralPrefabAsset& operator=(const ProceduralPrefabAsset& rhs) = delete;
|
||||
|
||||
const AZStd::string& GetTemplateName() const;
|
||||
void SetTemplateName(AZStd::string templateName);
|
||||
|
||||
AzToolsFramework::Prefab::TemplateId GetTemplateId() const;
|
||||
void SetTemplateId(AzToolsFramework::Prefab::TemplateId templateId);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
private:
|
||||
AZStd::string m_templateName;
|
||||
AzToolsFramework::Prefab::TemplateId m_templateId;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Prefab/ScriptingPrefabLoader.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
void ScriptingPrefabLoader::Connect(PrefabLoaderInterface* prefabLoaderInterface)
|
||||
{
|
||||
AZ_Assert(prefabLoaderInterface, "prefabLoaderInterface must not be null");
|
||||
|
||||
m_prefabLoaderInterface = prefabLoaderInterface;
|
||||
PrefabLoaderScriptingBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void ScriptingPrefabLoader::Disconnect()
|
||||
{
|
||||
PrefabLoaderScriptingBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
AZ::Outcome<AZStd::string, void> ScriptingPrefabLoader::SaveTemplateToString(TemplateId templateId)
|
||||
{
|
||||
AZStd::string json;
|
||||
|
||||
if (m_prefabLoaderInterface->SaveTemplateToString(templateId, json))
|
||||
{
|
||||
return AZ::Success(json);
|
||||
}
|
||||
|
||||
return AZ::Failure();
|
||||
}
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Prefab/PrefabLoaderInterface.h>
|
||||
#include <Prefab/PrefabLoaderScriptingBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
/**
|
||||
* The Scripting Prefab Loader handles scripting-friendly API requests for the prefab loader
|
||||
*/
|
||||
class ScriptingPrefabLoader
|
||||
: private PrefabLoaderScriptingBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ScriptingPrefabLoader, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(ScriptingPrefabLoader, "{ABC3C989-4D4F-41E7-B25B-B0FEF97177E6}");
|
||||
|
||||
void Connect(PrefabLoaderInterface* prefabLoaderInterface);
|
||||
void Disconnect();
|
||||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// PrefabLoaderRequestBus implementation
|
||||
AZ::Outcome<AZStd::string, void> SaveTemplateToString(TemplateId templateId) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrefabLoaderInterface* m_prefabLoaderInterface = nullptr;
|
||||
};
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/IO/FileOperations.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
@@ -78,13 +79,9 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(entitiesAndDescendants,
|
||||
&AzToolsFramework::ToolsApplicationRequestBus::Events::GatherEntitiesAndAllDescendents, AzToolsFramework::EntityIdList{ entityId });
|
||||
|
||||
// Retrieve the game folder so we can use that as a root with the passed in relative path
|
||||
const char* gameFolder = nullptr;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(gameFolder, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAbsoluteDevGameFolderPath);
|
||||
|
||||
// Join our relative path with the game folder to get a full path to the desired asset
|
||||
AZStd::string assetFullPath;
|
||||
AzFramework::StringFunc::Path::Join(gameFolder, assetPath, assetFullPath);
|
||||
AZ::IO::FixedMaxPath assetFullPath = AZ::Utils::GetProjectPath();
|
||||
assetFullPath /= assetPath;
|
||||
|
||||
// Call SliceUtilities::MakeNewSlice with all user input prompts disabled
|
||||
bool success = AzToolsFramework::SliceUtilities::MakeNewSlice(entitiesAndDescendants,
|
||||
|
||||
@@ -718,7 +718,7 @@ namespace AzToolsFramework
|
||||
|
||||
if (!fullPathFound)
|
||||
{
|
||||
assetFullPath = AZStd::string::format("@devassets@/%s", sliceAssetPath.c_str());
|
||||
assetFullPath = AZStd::string::format("@projectroot@/%s", sliceAssetPath.c_str());
|
||||
}
|
||||
|
||||
return Commit(assetFullPath.c_str(), preSaveCallback, postSaveCallback, sliceCommitFlags);
|
||||
@@ -1020,13 +1020,13 @@ namespace AzToolsFramework
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
AZ_Assert(fileIO, "File IO is not initialized.");
|
||||
|
||||
AZStd::string devAssetPath = fileIO->GetAlias("@devassets@");
|
||||
AZStd::string devAssetPath = fileIO->GetAlias("@projectroot@");
|
||||
AZStd::string userPath = fileIO->GetAlias("@user@");
|
||||
AZStd::string tempPath = fullPath;
|
||||
EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, devAssetPath);
|
||||
EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, userPath);
|
||||
EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, tempPath);
|
||||
AzFramework::StringFunc::Replace(tempPath, "@devassets@", devAssetPath.c_str());
|
||||
AzFramework::StringFunc::Replace(tempPath, "@projectroot@", devAssetPath.c_str());
|
||||
AzFramework::StringFunc::Replace(tempPath, devAssetPath.c_str(), userPath.c_str());
|
||||
tempPath.append(".slicetemp");
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace AzToolsFramework
|
||||
typedef SharedThumbnailKey BusIdType;
|
||||
|
||||
//! notify product thumbnail that the data is ready
|
||||
virtual void ThumbnailRendered(QPixmap& thumbnailImage) = 0;
|
||||
virtual void ThumbnailRendered(const QPixmap& thumbnailImage) = 0;
|
||||
//! notify product thumbnail that the thumbnail failed to render
|
||||
virtual void ThumbnailFailedToRender() = 0;
|
||||
};
|
||||
|
||||
+2
-2
@@ -378,11 +378,11 @@ namespace AzToolsFramework
|
||||
// If this layer is being loaded, it won't have a level save dependency yet, so clear that flag.
|
||||
m_mustSaveLevelWhenLayerSaves = false;
|
||||
QString fullPathName = levelPakFile;
|
||||
if (fullPathName.contains("@devassets@"))
|
||||
if (fullPathName.contains("@projectroot@"))
|
||||
{
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
// Resolving the path through resolvepath would normalize and lowcase it, and in this case, we don't want that.
|
||||
fullPathName.replace("@devassets@", fileIO->GetAlias("@devassets@"));
|
||||
fullPathName.replace("@projectroot@", fileIO->GetAlias("@projectroot@"));
|
||||
}
|
||||
|
||||
QFileInfo fileNameInfo(fullPathName);
|
||||
|
||||
+1
-1
@@ -1025,7 +1025,7 @@ namespace AzToolsFramework
|
||||
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/LuaScript.svg")
|
||||
->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo<AZ::ScriptAsset>::Uuid())
|
||||
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Script.png")
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/lua-script/")
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/scripting/lua-script/")
|
||||
->DataElement("AssetRef", &ScriptEditorComponent::m_scriptAsset, "Script", "Which script to use")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &ScriptEditorComponent::ScriptHasChanged)
|
||||
->Attribute("BrowseIcon", ":/stylesheet/img/UI20/browse-edit-select-files.svg")
|
||||
|
||||
+33
-13
@@ -37,51 +37,71 @@ namespace AzToolsFramework
|
||||
return m_handlerId;
|
||||
}
|
||||
|
||||
QString EditorEntityUiHandlerBase::GenerateItemInfoString(AZ::EntityId /*entityId*/) const
|
||||
QString EditorEntityUiHandlerBase::GenerateItemInfoString([[maybe_unused]] AZ::EntityId entityId) const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString EditorEntityUiHandlerBase::GenerateItemTooltip(AZ::EntityId /*entityId*/) const
|
||||
QString EditorEntityUiHandlerBase::GenerateItemTooltip([[maybe_unused]] AZ::EntityId entityId) const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QIcon EditorEntityUiHandlerBase::GenerateItemIcon(AZ::EntityId /*entityId*/) const
|
||||
QIcon EditorEntityUiHandlerBase::GenerateItemIcon([[maybe_unused]] AZ::EntityId entityId) const
|
||||
{
|
||||
return QIcon();
|
||||
}
|
||||
|
||||
bool EditorEntityUiHandlerBase::CanToggleLockVisibility(AZ::EntityId /*entityId*/) const
|
||||
bool EditorEntityUiHandlerBase::CanToggleLockVisibility([[maybe_unused]] AZ::EntityId entityId) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditorEntityUiHandlerBase::CanRename(AZ::EntityId /*entityId*/) const
|
||||
bool EditorEntityUiHandlerBase::CanRename([[maybe_unused]] AZ::EntityId entityId) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditorEntityUiHandlerBase::PaintItemBackground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const
|
||||
void EditorEntityUiHandlerBase::PaintItemBackground(
|
||||
[[maybe_unused]] QPainter* painter,
|
||||
[[maybe_unused]] const QStyleOptionViewItem& option,
|
||||
[[maybe_unused]] const QModelIndex& index) const
|
||||
{
|
||||
}
|
||||
|
||||
void EditorEntityUiHandlerBase::PaintDescendantBackground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/,
|
||||
const QModelIndex& /*descendantIndex*/) const
|
||||
void EditorEntityUiHandlerBase::PaintDescendantBackground(
|
||||
[[maybe_unused]] QPainter* painter,
|
||||
[[maybe_unused]] const QStyleOptionViewItem& option,
|
||||
[[maybe_unused]] const QModelIndex& index,
|
||||
[[maybe_unused]] const QModelIndex& descendantIndex) const
|
||||
{
|
||||
}
|
||||
|
||||
void EditorEntityUiHandlerBase::PaintDescendantBranchBackground(QPainter* /*painter*/, const QTreeView* /*view*/, const QRect& /*rect*/,
|
||||
const QModelIndex& /*index*/, const QModelIndex& /*descendantIndex*/) const
|
||||
void EditorEntityUiHandlerBase::PaintDescendantBranchBackground(
|
||||
[[maybe_unused]] QPainter* painter,
|
||||
[[maybe_unused]] const QTreeView* view,
|
||||
[[maybe_unused]] const QRect& rect,
|
||||
[[maybe_unused]] const QModelIndex& index,
|
||||
[[maybe_unused]] const QModelIndex& descendantIndex) const
|
||||
{
|
||||
}
|
||||
|
||||
void EditorEntityUiHandlerBase::PaintItemForeground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const
|
||||
void EditorEntityUiHandlerBase::PaintItemForeground(
|
||||
[[maybe_unused]] QPainter* painter,
|
||||
[[maybe_unused]] const QStyleOptionViewItem& option,
|
||||
[[maybe_unused]] const QModelIndex& index) const
|
||||
{
|
||||
}
|
||||
|
||||
void EditorEntityUiHandlerBase::PaintDescendantForeground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/,
|
||||
const QModelIndex& /*descendantIndex*/) const
|
||||
void EditorEntityUiHandlerBase::PaintDescendantForeground(
|
||||
[[maybe_unused]] QPainter* painter,
|
||||
[[maybe_unused]] const QStyleOptionViewItem& option,
|
||||
[[maybe_unused]] const QModelIndex& index,
|
||||
[[maybe_unused]] const QModelIndex& descendantIndex) const
|
||||
{
|
||||
}
|
||||
|
||||
void EditorEntityUiHandlerBase::OnDoubleClick([[maybe_unused]] AZ::EntityId entityId) const
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -61,6 +61,9 @@ namespace AzToolsFramework
|
||||
virtual void PaintDescendantForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index,
|
||||
const QModelIndex& descendantIndex) const;
|
||||
|
||||
//! Triggered when the entity is double clicked in the Outliner.
|
||||
virtual void OnDoubleClick(AZ::EntityId entityId) const;
|
||||
|
||||
private:
|
||||
EditorEntityUiHandlerId m_handlerId = 0;
|
||||
};
|
||||
|
||||
+23
-2
@@ -88,6 +88,7 @@ namespace AzToolsFramework
|
||||
|
||||
EntityOutlinerListModel::~EntityOutlinerListModel()
|
||||
{
|
||||
ContainerEntityNotificationBus::Handler::BusDisconnect();
|
||||
EditorEntityInfoNotificationBus::Handler::BusDisconnect();
|
||||
EditorEntityContextNotificationBus::Handler::BusDisconnect();
|
||||
ToolsApplicationEvents::Bus::Handler::BusDisconnect();
|
||||
@@ -105,6 +106,12 @@ namespace AzToolsFramework
|
||||
EntityCompositionNotificationBus::Handler::BusConnect();
|
||||
AZ::EntitySystemBus::Handler::BusConnect();
|
||||
|
||||
AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult(
|
||||
editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId);
|
||||
|
||||
ContainerEntityNotificationBus::Handler::BusConnect(editorEntityContextId);
|
||||
|
||||
m_editorEntityUiInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get();
|
||||
AZ_Assert(m_editorEntityUiInterface != nullptr,
|
||||
"EntityOutlinerListModel requires a EditorEntityUiInterface instance on Initialize.");
|
||||
@@ -1333,12 +1340,26 @@ namespace AzToolsFramework
|
||||
emit EnableSelectionUpdates(true);
|
||||
}
|
||||
|
||||
void EntityOutlinerListModel::OnEntityRuntimeActivationChanged(AZ::EntityId entityId, bool activeOnStart)
|
||||
void EntityOutlinerListModel::OnEntityRuntimeActivationChanged(AZ::EntityId entityId, [[maybe_unused]] bool activeOnStart)
|
||||
{
|
||||
AZ_UNUSED(activeOnStart);
|
||||
QueueEntityUpdate(entityId);
|
||||
}
|
||||
|
||||
void EntityOutlinerListModel::OnContainerEntityStatusChanged(AZ::EntityId entityId, [[maybe_unused]] bool open)
|
||||
{
|
||||
QModelIndex changedIndex = GetIndexFromEntity(entityId);
|
||||
|
||||
// Trigger a refresh of all direct children so that they can be shown or hidden appropriately.
|
||||
int numChildren = rowCount(changedIndex);
|
||||
if (numChildren > 0)
|
||||
{
|
||||
emit dataChanged(index(0, 0, changedIndex), index(numChildren - 1, ColumnCount - 1, changedIndex));
|
||||
}
|
||||
|
||||
// Always expand containers
|
||||
QueueEntityToExpand(entityId, true);
|
||||
}
|
||||
|
||||
void EntityOutlinerListModel::OnEntityInfoUpdatedRemoveChildBegin([[maybe_unused]] AZ::EntityId parentId, [[maybe_unused]] AZ::EntityId childId)
|
||||
{
|
||||
//add/remove operations trigger selection change signals which assert and break undo/redo operations in progress in inspector etc.
|
||||
|
||||
+5
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <AzToolsFramework/API/EntityCompositionNotificationBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityRuntimeActivationBus.h>
|
||||
@@ -54,6 +55,7 @@ namespace AzToolsFramework
|
||||
, private EntityCompositionNotificationBus::Handler
|
||||
, private EditorEntityRuntimeActivationChangeNotificationBus::Handler
|
||||
, private AZ::EntitySystemBus::Handler
|
||||
, private ContainerEntityNotificationBus::Handler
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
@@ -216,6 +218,9 @@ namespace AzToolsFramework
|
||||
// EditorEntityRuntimeActivationChangeNotificationBus::Handler
|
||||
void OnEntityRuntimeActivationChanged(AZ::EntityId entityId, bool activeOnStart) override;
|
||||
|
||||
// ContainerEntityNotificationBus overrides ...
|
||||
void OnContainerEntityStatusChanged(AZ::EntityId entityId, bool open) override;
|
||||
|
||||
// Drag/Drop of components from Component Palette.
|
||||
bool dropMimeDataComponentPalette(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent);
|
||||
|
||||
|
||||
+22
@@ -11,6 +11,8 @@
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
|
||||
#include "EntityOutlinerListModel.hxx"
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -19,6 +21,10 @@ namespace AzToolsFramework
|
||||
EntityOutlinerSortFilterProxyModel::EntityOutlinerSortFilterProxyModel(QObject* pParent)
|
||||
: QSortFilterProxyModel(pParent)
|
||||
{
|
||||
m_containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
|
||||
AZ_Assert(
|
||||
m_containerEntityInterface != nullptr,
|
||||
"EntityOutlinerContainerProxyModel requires a ContainerEntityInterface instance on construction.");
|
||||
}
|
||||
|
||||
void EntityOutlinerSortFilterProxyModel::UpdateFilter()
|
||||
@@ -26,8 +32,24 @@ namespace AzToolsFramework
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void EntityOutlinerSortFilterProxyModel::setSourceModel(QAbstractItemModel* sourceModel)
|
||||
{
|
||||
QSortFilterProxyModel::setSourceModel(sourceModel);
|
||||
|
||||
m_listModel = qobject_cast<EntityOutlinerListModel*>(sourceModel);
|
||||
AZ_Assert(m_listModel != nullptr, "EntityOutlinerContainerProxyModel requires an EntityOutlinerListModel as its source .");
|
||||
}
|
||||
|
||||
bool EntityOutlinerSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
|
||||
{
|
||||
// Retrieve the entityId of the parent entity
|
||||
AZ::EntityId parentEntityId = m_listModel->GetEntityFromIndex(sourceParent);
|
||||
|
||||
if(!m_containerEntityInterface->IsContainerOpen(parentEntityId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
QVariant visibilityData = sourceModel()->data(index, EntityOutlinerListModel::VisibilityRole);
|
||||
return visibilityData.isValid() ? visibilityData.toBool() : true;
|
||||
|
||||
+8
-4
@@ -19,11 +19,12 @@
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class ContainerEntityInterface;
|
||||
class EntityOutlinerListModel;
|
||||
|
||||
/*!
|
||||
* Enables the Outliner to filter entries based on search string.
|
||||
* Enables the Outliner to do custom sorting on entries.
|
||||
*/
|
||||
//! Enables the Outliner to filter entries based on search string.
|
||||
//! Enables the Outliner to do custom sorting on entries.
|
||||
//! Enforces the correct rendering for container entities.
|
||||
class EntityOutlinerSortFilterProxyModel
|
||||
: public QSortFilterProxyModel
|
||||
{
|
||||
@@ -37,12 +38,15 @@ namespace AzToolsFramework
|
||||
void UpdateFilter();
|
||||
|
||||
// Qt overrides
|
||||
void setSourceModel(QAbstractItemModel* sourceModel) override;
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
|
||||
bool lessThan(const QModelIndex& left, const QModelIndex& right) const override;
|
||||
void sort(int column, Qt::SortOrder order) override;
|
||||
|
||||
private:
|
||||
QString m_filterName;
|
||||
EntityOutlinerListModel* m_listModel = nullptr;
|
||||
ContainerEntityInterface* m_containerEntityInterface = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+24
-10
@@ -26,6 +26,7 @@
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
#include <AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.hxx>
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h>
|
||||
#include <AzToolsFramework/UI/Outliner/EntityOutlinerDisplayOptionsMenu.h>
|
||||
@@ -198,6 +199,7 @@ namespace AzToolsFramework
|
||||
|
||||
m_proxyModel = aznew EntityOutlinerSortFilterProxyModel(this);
|
||||
m_proxyModel->setSourceModel(m_listModel);
|
||||
|
||||
m_gui->m_objectTree->setModel(m_proxyModel);
|
||||
|
||||
// Link up signals for informing the model of tree changes using the proxy as an intermediary
|
||||
@@ -291,8 +293,7 @@ namespace AzToolsFramework
|
||||
EntityOutlinerModelNotificationBus::Handler::BusConnect();
|
||||
ToolsApplicationEvents::Bus::Handler::BusConnect();
|
||||
EditorEntityContextNotificationBus::Handler::BusConnect();
|
||||
ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect(
|
||||
GetEntityContextId());
|
||||
ViewportEditorModeNotificationsBus::Handler::BusConnect(GetEntityContextId());
|
||||
EditorEntityInfoNotificationBus::Handler::BusConnect();
|
||||
Prefab::PrefabPublicNotificationBus::Handler::BusConnect();
|
||||
EditorWindowUIRequestBus::Handler::BusConnect();
|
||||
@@ -302,7 +303,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
EditorWindowUIRequestBus::Handler::BusDisconnect();
|
||||
Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect();
|
||||
ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect();
|
||||
ViewportEditorModeNotificationsBus::Handler::BusDisconnect();
|
||||
EditorEntityInfoNotificationBus::Handler::BusDisconnect();
|
||||
EditorPickModeNotificationBus::Handler::BusDisconnect();
|
||||
EntityHighlightMessages::Bus::Handler::BusDisconnect();
|
||||
@@ -323,7 +324,8 @@ namespace AzToolsFramework
|
||||
// Currently, the first behavior is implemented.
|
||||
void EntityOutlinerWidget::OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
if (m_selectionChangeInProgress || !m_enableSelectionUpdates)
|
||||
if (m_selectionChangeInProgress || !m_enableSelectionUpdates
|
||||
|| (selected.empty() && deselected.empty()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -905,8 +907,12 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerWidget::OnTreeItemDoubleClicked(const QModelIndex& /*index*/)
|
||||
void EntityOutlinerWidget::OnTreeItemDoubleClicked(const QModelIndex& index)
|
||||
{
|
||||
if (AZ::EntityId entityId = GetEntityIdFromIndex(index); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId))
|
||||
{
|
||||
entityUiHandler->OnDoubleClick(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerWidget::OnTreeItemExpanded(const QModelIndex& index)
|
||||
@@ -1123,14 +1129,22 @@ namespace AzToolsFramework
|
||||
EnableUi(enable);
|
||||
}
|
||||
|
||||
void EntityOutlinerWidget::EnteredComponentMode([[maybe_unused]] const AZStd::vector<AZ::Uuid>& componentModeTypes)
|
||||
void EntityOutlinerWidget::OnEditorModeActivated(
|
||||
[[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode)
|
||||
{
|
||||
EnableUi(false);
|
||||
if (mode == ViewportEditorMode::Component)
|
||||
{
|
||||
EnableUi(false);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerWidget::LeftComponentMode([[maybe_unused]] const AZStd::vector<AZ::Uuid>& componentModeTypes)
|
||||
void EntityOutlinerWidget::OnEditorModeDeactivated(
|
||||
[[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode)
|
||||
{
|
||||
EnableUi(true);
|
||||
if (mode == ViewportEditorMode::Component)
|
||||
{
|
||||
EnableUi(true);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerWidget::OnPrefabInstancePropagationBegin()
|
||||
@@ -1142,7 +1156,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
QTimer::singleShot(1, this, [this]() {
|
||||
m_gui->m_objectTree->setUpdatesEnabled(true);
|
||||
m_gui->m_objectTree->expand(m_proxyModel->index(0,0));
|
||||
m_gui->m_objectTree->expandToDepth(0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+9
-5
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicNotificationBus.h>
|
||||
@@ -41,6 +41,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
class EditorEntityUiInterface;
|
||||
class EntityOutlinerListModel;
|
||||
class EntityOutlinerContainerProxyModel;
|
||||
class EntityOutlinerSortFilterProxyModel;
|
||||
|
||||
namespace EntityOutliner
|
||||
@@ -58,7 +59,7 @@ namespace AzToolsFramework
|
||||
, private ToolsApplicationEvents::Bus::Handler
|
||||
, private EditorEntityContextNotificationBus::Handler
|
||||
, private EditorEntityInfoNotificationBus::Handler
|
||||
, private ComponentModeFramework::EditorComponentModeNotificationBus::Handler
|
||||
, private ViewportEditorModeNotificationsBus::Handler
|
||||
, private Prefab::PrefabPublicNotificationBus::Handler
|
||||
, private EditorWindowUIRequestBus::Handler
|
||||
{
|
||||
@@ -100,9 +101,11 @@ namespace AzToolsFramework
|
||||
void OnEntityInfoUpdatedAddChildEnd(AZ::EntityId /*parentId*/, AZ::EntityId /*childId*/) override;
|
||||
void OnEntityInfoUpdatedName(AZ::EntityId entityId, const AZStd::string& /*name*/) override;
|
||||
|
||||
// EditorComponentModeNotificationBus
|
||||
void EnteredComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes) override;
|
||||
void LeftComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes) override;
|
||||
// ViewportEditorModeNotificationsBus overrides ...
|
||||
void OnEditorModeActivated(
|
||||
const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override;
|
||||
void OnEditorModeDeactivated(
|
||||
const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override;
|
||||
|
||||
// PrefabPublicNotificationBus
|
||||
void OnPrefabInstancePropagationBegin() override;
|
||||
@@ -117,6 +120,7 @@ namespace AzToolsFramework
|
||||
|
||||
Ui::EntityOutlinerWidgetUI* m_gui;
|
||||
EntityOutlinerListModel* m_listModel;
|
||||
EntityOutlinerContainerProxyModel* m_containerModel;
|
||||
EntityOutlinerSortFilterProxyModel* m_proxyModel;
|
||||
AZ::u64 m_selectionContextId;
|
||||
AZStd::vector<AZ::EntityId> m_selectedEntityIds;
|
||||
|
||||
+120
-17
@@ -13,6 +13,7 @@
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
@@ -22,8 +23,12 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorLayerComponentBus.h>
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiInterface.h>
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h>
|
||||
@@ -34,7 +39,6 @@
|
||||
#include <AzQtComponents/Components/StyleManager.h>
|
||||
#include <AzQtComponents/Components/Widgets/CardHeader.h>
|
||||
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QDialog>
|
||||
@@ -51,14 +55,13 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
|
||||
ContainerEntityInterface* PrefabIntegrationManager::s_containerEntityInterface = nullptr;
|
||||
EditorEntityUiInterface* PrefabIntegrationManager::s_editorEntityUiInterface = nullptr;
|
||||
PrefabFocusInterface* PrefabIntegrationManager::s_prefabFocusInterface = nullptr;
|
||||
PrefabFocusPublicInterface* PrefabIntegrationManager::s_prefabFocusPublicInterface = nullptr;
|
||||
PrefabLoaderInterface* PrefabIntegrationManager::s_prefabLoaderInterface = nullptr;
|
||||
PrefabPublicInterface* PrefabIntegrationManager::s_prefabPublicInterface = nullptr;
|
||||
PrefabSystemComponentInterface* PrefabIntegrationManager::s_prefabSystemComponentInterface = nullptr;
|
||||
@@ -89,6 +92,13 @@ namespace AzToolsFramework
|
||||
|
||||
PrefabIntegrationManager::PrefabIntegrationManager()
|
||||
{
|
||||
s_containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
|
||||
if (s_containerEntityInterface == nullptr)
|
||||
{
|
||||
AZ_Assert(false, "Prefab - could not get ContainerEntityInterface on PrefabIntegrationManager construction.");
|
||||
return;
|
||||
}
|
||||
|
||||
s_editorEntityUiInterface = AZ::Interface<EditorEntityUiInterface>::Get();
|
||||
if (s_editorEntityUiInterface == nullptr)
|
||||
{
|
||||
@@ -117,14 +127,15 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
s_prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
|
||||
if (s_prefabFocusInterface == nullptr)
|
||||
s_prefabFocusPublicInterface = AZ::Interface<PrefabFocusPublicInterface>::Get();
|
||||
if (s_prefabFocusPublicInterface == nullptr)
|
||||
{
|
||||
AZ_Assert(false, "Prefab - could not get PrefabFocusInterface on PrefabIntegrationManager construction.");
|
||||
AZ_Assert(false, "Prefab - could not get PrefabFocusPublicInterface on PrefabIntegrationManager construction.");
|
||||
return;
|
||||
}
|
||||
|
||||
EditorContextMenuBus::Handler::BusConnect();
|
||||
EditorEventsBus::Handler::BusConnect();
|
||||
PrefabInstanceContainerNotificationBus::Handler::BusConnect();
|
||||
AZ::Interface<PrefabIntegrationInterface>::Register(this);
|
||||
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusConnect(s_prefabFileExtension);
|
||||
@@ -135,6 +146,7 @@ namespace AzToolsFramework
|
||||
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusDisconnect();
|
||||
AZ::Interface<PrefabIntegrationInterface>::Unregister(this);
|
||||
PrefabInstanceContainerNotificationBus::Handler::BusDisconnect();
|
||||
EditorEventsBus::Handler::BusDisconnect();
|
||||
EditorContextMenuBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
@@ -210,6 +222,16 @@ namespace AzToolsFramework
|
||||
instantiateAction, &QAction::triggered, instantiateAction, [] { ContextMenu_InstantiatePrefab(); });
|
||||
}
|
||||
|
||||
// Instantiate Procedural Prefab
|
||||
if (AZ::Prefab::ProceduralPrefabAsset::UseProceduralPrefabs())
|
||||
{
|
||||
QAction* action = menu->addAction(QObject::tr("Instantiate Procedural Prefab..."));
|
||||
action->setToolTip(QObject::tr("Instantiates a procedural prefab file in a prefab."));
|
||||
|
||||
QObject::connect(
|
||||
action, &QAction::triggered, action, [] { ContextMenu_InstantiateProceduralPrefab(); });
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
bool itemWasShown = false;
|
||||
@@ -223,12 +245,8 @@ namespace AzToolsFramework
|
||||
if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity))
|
||||
{
|
||||
// Edit Prefab
|
||||
if (prefabWipFeaturesEnabled)
|
||||
if (prefabWipFeaturesEnabled && !s_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(selectedEntity))
|
||||
{
|
||||
bool beingEdited = s_prefabFocusInterface->IsOwningPrefabBeingFocused(selectedEntity);
|
||||
|
||||
if (!beingEdited)
|
||||
{
|
||||
QAction* editAction = menu->addAction(QObject::tr("Edit Prefab"));
|
||||
editAction->setToolTip(QObject::tr("Edit the prefab in focus mode."));
|
||||
|
||||
@@ -237,7 +255,6 @@ namespace AzToolsFramework
|
||||
});
|
||||
|
||||
itemWasShown = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Save Prefab
|
||||
@@ -291,6 +308,11 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::OnEscape()
|
||||
{
|
||||
s_prefabFocusPublicInterface->FocusOnOwningPrefab(AZ::EntityId());
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const
|
||||
{
|
||||
auto instantiatePrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(sourceFilePath, parentId, position);
|
||||
@@ -307,7 +329,7 @@ namespace AzToolsFramework
|
||||
// temporarily null after QFileDialogs close, which we need in order to
|
||||
// be able to parent our message dialogs properly
|
||||
QWidget* activeWindow = QApplication::activeWindow();
|
||||
const AZStd::string prefabFilesPath = "@devassets@/Prefabs";
|
||||
const AZStd::string prefabFilesPath = "@projectroot@/Prefabs";
|
||||
|
||||
// Remove Level entity if it's part of the list
|
||||
|
||||
@@ -427,9 +449,41 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::ContextMenu_InstantiateProceduralPrefab()
|
||||
{
|
||||
AZStd::string prefabAssetPath;
|
||||
bool hasUserForProceduralPrefabAsset = QueryUserForProceduralPrefabAsset(prefabAssetPath);
|
||||
|
||||
if (hasUserForProceduralPrefabAsset)
|
||||
{
|
||||
AZ::EntityId parentId;
|
||||
AZ::Vector3 position = AZ::Vector3::CreateZero();
|
||||
|
||||
EntityIdList selectedEntities;
|
||||
ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequests::GetSelectedEntities);
|
||||
if (selectedEntities.size() == 1)
|
||||
{
|
||||
parentId = selectedEntities.front();
|
||||
AZ::TransformBus::EventResult(position, parentId, &AZ::TransformInterface::GetWorldTranslation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise return since it needs to be inside an authored prefab
|
||||
return;
|
||||
}
|
||||
|
||||
// Instantiating from context menu always puts the instance at the root level
|
||||
auto createPrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(prefabAssetPath, parentId, position);
|
||||
if (!createPrefabOutcome.IsSuccess())
|
||||
{
|
||||
WarnUserOfError("Prefab Instantiation Error", createPrefabOutcome.GetError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::ContextMenu_EditPrefab(AZ::EntityId containerEntity)
|
||||
{
|
||||
s_prefabFocusInterface->FocusOnOwningPrefab(containerEntity);
|
||||
s_prefabFocusPublicInterface->FocusOnOwningPrefab(containerEntity);
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::ContextMenu_SavePrefab(AZ::EntityId containerEntity)
|
||||
@@ -682,6 +736,33 @@ namespace AzToolsFramework
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PrefabIntegrationManager::QueryUserForProceduralPrefabAsset(AZStd::string& outPrefabAssetPath)
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
auto selection = AssetBrowser::AssetSelectionModel::AssetTypeSelection(azrtti_typeid<AZ::Prefab::ProceduralPrefabAsset>());
|
||||
EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection);
|
||||
|
||||
if (!selection.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto product = azrtti_cast<const ProductAssetBrowserEntry*>(selection.GetResult());
|
||||
if (product == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
outPrefabAssetPath = product->GetRelativePath();
|
||||
|
||||
auto asset = AZ::Data::AssetManager::Instance().GetAsset(
|
||||
product->GetAssetId(),
|
||||
azrtti_typeid<AZ::Prefab::ProceduralPrefabAsset>(),
|
||||
AZ::Data::AssetLoadBehavior::Default);
|
||||
|
||||
return asset.BlockUntilLoadComplete() != AZ::Data::AssetData::AssetStatus::Error;
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::WarnUserOfError(AZStd::string_view title, AZStd::string_view message)
|
||||
{
|
||||
QWidget* activeWindow = QApplication::activeWindow();
|
||||
@@ -1057,6 +1138,7 @@ namespace AzToolsFramework
|
||||
|
||||
void PrefabIntegrationManager::OnPrefabComponentActivate(AZ::EntityId entityId)
|
||||
{
|
||||
// Register entity to appropriate UI Handler for UI overrides
|
||||
if (s_prefabPublicInterface->IsLevelInstanceContainerEntity(entityId))
|
||||
{
|
||||
s_editorEntityUiInterface->RegisterEntity(entityId, m_levelRootUiHandler.GetHandlerId());
|
||||
@@ -1064,11 +1146,32 @@ namespace AzToolsFramework
|
||||
else
|
||||
{
|
||||
s_editorEntityUiInterface->RegisterEntity(entityId, m_prefabUiHandler.GetHandlerId());
|
||||
|
||||
bool prefabWipFeaturesEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
||||
|
||||
if (prefabWipFeaturesEnabled)
|
||||
{
|
||||
// Register entity as a container
|
||||
s_containerEntityInterface->RegisterEntityAsContainer(entityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::OnPrefabComponentDeactivate(AZ::EntityId entityId)
|
||||
{
|
||||
bool prefabWipFeaturesEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
||||
|
||||
if (prefabWipFeaturesEnabled && !s_prefabPublicInterface->IsLevelInstanceContainerEntity(entityId))
|
||||
{
|
||||
// Unregister entity as a container
|
||||
s_containerEntityInterface->UnregisterEntityAsContainer(entityId);
|
||||
}
|
||||
|
||||
// Unregister entity from UI Handler
|
||||
s_editorEntityUiInterface->UnregisterEntity(entityId);
|
||||
}
|
||||
|
||||
@@ -1290,7 +1393,7 @@ namespace AzToolsFramework
|
||||
|
||||
AZStd::unique_ptr<AzQtComponents::Card> PrefabIntegrationManager::ConstructUnsavedPrefabsCard(TemplateId templateId)
|
||||
{
|
||||
FlowLayout* unsavedPrefabsLayout = new FlowLayout(AzToolsFramework::GetActiveWindow());
|
||||
FlowLayout* unsavedPrefabsLayout = new FlowLayout(nullptr);
|
||||
|
||||
AZStd::set<AZ::IO::PathView> dirtyTemplatePaths = s_prefabSystemComponentInterface->GetDirtyTemplatePaths(templateId);
|
||||
|
||||
|
||||
+15
-6
@@ -26,9 +26,11 @@
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class ContainerEntityInterface;
|
||||
|
||||
namespace Prefab
|
||||
{
|
||||
class PrefabFocusInterface;
|
||||
class PrefabFocusPublicInterface;
|
||||
class PrefabLoaderInterface;
|
||||
|
||||
//! Structure for saving/retrieving user settings related to prefab workflows.
|
||||
@@ -49,6 +51,7 @@ namespace AzToolsFramework
|
||||
|
||||
class PrefabIntegrationManager final
|
||||
: public EditorContextMenuBus::Handler
|
||||
, public EditorEventsBus::Handler
|
||||
, public AssetBrowser::AssetBrowserSourceDropBus::Handler
|
||||
, public PrefabInstanceContainerNotificationBus::Handler
|
||||
, public PrefabIntegrationInterface
|
||||
@@ -62,19 +65,22 @@ namespace AzToolsFramework
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
// EditorContextMenuBus...
|
||||
// EditorContextMenuBus overrides ...
|
||||
int GetMenuPosition() const override;
|
||||
AZStd::string GetMenuIdentifier() const override;
|
||||
void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override;
|
||||
|
||||
// EntityOutlinerSourceDropHandlingBus...
|
||||
// EditorEventsBus overrides ...
|
||||
void OnEscape();
|
||||
|
||||
// EntityOutlinerSourceDropHandlingBus overrides ...
|
||||
void HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const override;
|
||||
|
||||
// PrefabInstanceContainerNotificationBus...
|
||||
// PrefabInstanceContainerNotificationBus overrides ...
|
||||
void OnPrefabComponentActivate(AZ::EntityId entityId) override;
|
||||
void OnPrefabComponentDeactivate(AZ::EntityId entityId) override;
|
||||
|
||||
// PrefabIntegrationInterface...
|
||||
// PrefabIntegrationInterface overrides ...
|
||||
AZ::EntityId CreateNewEntityAtPosition(const AZ::Vector3& position, AZ::EntityId parentId) override;
|
||||
int ExecuteClosePrefabDialog(TemplateId templateId) override;
|
||||
void ExecuteSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference) override;
|
||||
@@ -89,6 +95,7 @@ namespace AzToolsFramework
|
||||
// Context menu item handlers
|
||||
static void ContextMenu_CreatePrefab(AzToolsFramework::EntityIdList selectedEntities);
|
||||
static void ContextMenu_InstantiatePrefab();
|
||||
static void ContextMenu_InstantiateProceduralPrefab();
|
||||
static void ContextMenu_EditPrefab(AZ::EntityId containerEntity);
|
||||
static void ContextMenu_SavePrefab(AZ::EntityId containerEntity);
|
||||
static void ContextMenu_DeleteSelected();
|
||||
@@ -99,6 +106,7 @@ namespace AzToolsFramework
|
||||
const AZStd::string& suggestedName, const char* initialTargetDirectory, AZ::u32 prefabUserSettingsId, QWidget* activeWindow,
|
||||
AZStd::string& outPrefabName, AZStd::string& outPrefabFilePath);
|
||||
static bool QueryUserForPrefabFilePath(AZStd::string& outPrefabFilePath);
|
||||
static bool QueryUserForProceduralPrefabAsset(AZStd::string& outPrefabAssetPath);
|
||||
static void WarnUserOfError(AZStd::string_view title, AZStd::string_view message);
|
||||
|
||||
// Path and filename generation
|
||||
@@ -134,8 +142,9 @@ namespace AzToolsFramework
|
||||
|
||||
static const AZStd::string s_prefabFileExtension;
|
||||
|
||||
static ContainerEntityInterface* s_containerEntityInterface;
|
||||
static EditorEntityUiInterface* s_editorEntityUiInterface;
|
||||
static PrefabFocusInterface* s_prefabFocusInterface;
|
||||
static PrefabFocusPublicInterface* s_prefabFocusPublicInterface;
|
||||
static PrefabLoaderInterface* s_prefabLoaderInterface;
|
||||
static PrefabPublicInterface* s_prefabPublicInterface;
|
||||
static PrefabSystemComponentInterface* s_prefabSystemComponentInterface;
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabUiHandler.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx>
|
||||
|
||||
@@ -33,10 +35,10 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
m_prefabFocusInterface = AZ::Interface<Prefab::PrefabFocusInterface>::Get();
|
||||
if (m_prefabFocusInterface == nullptr)
|
||||
m_prefabFocusPublicInterface = AZ::Interface<Prefab::PrefabFocusPublicInterface>::Get();
|
||||
if (m_prefabFocusPublicInterface == nullptr)
|
||||
{
|
||||
AZ_Assert(false, "PrefabUiHandler - could not get PrefabFocusInterface on PrefabUiHandler construction.");
|
||||
AZ_Assert(false, "PrefabUiHandler - could not get PrefabFocusPublicInterface on PrefabUiHandler construction.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -81,7 +83,7 @@ namespace AzToolsFramework
|
||||
|
||||
QIcon PrefabUiHandler::GenerateItemIcon(AZ::EntityId entityId) const
|
||||
{
|
||||
if (m_prefabFocusInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
{
|
||||
return QIcon(m_prefabEditIconPath);
|
||||
}
|
||||
@@ -103,7 +105,7 @@ namespace AzToolsFramework
|
||||
const bool hasVisibleChildren = index.data(EntityOutlinerListModel::ExpandedRole).value<bool>() && index.model()->hasChildren(index);
|
||||
|
||||
QColor backgroundColor = m_prefabCapsuleColor;
|
||||
if (m_prefabFocusInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
{
|
||||
backgroundColor = m_prefabCapsuleEditColor;
|
||||
}
|
||||
@@ -189,7 +191,7 @@ namespace AzToolsFramework
|
||||
const bool isLastColumn = descendantIndex.column() == EntityOutlinerListModel::ColumnLockToggle;
|
||||
|
||||
QColor borderColor = m_prefabCapsuleColor;
|
||||
if (m_prefabFocusInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
{
|
||||
borderColor = m_prefabCapsuleEditColor;
|
||||
}
|
||||
@@ -317,4 +319,17 @@ namespace AzToolsFramework
|
||||
|
||||
return Internal_GetLastVisibleChild(model, lastChild);
|
||||
}
|
||||
|
||||
void PrefabUiHandler::OnDoubleClick(AZ::EntityId entityId) const
|
||||
{
|
||||
bool prefabWipFeaturesEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
||||
|
||||
if (prefabWipFeaturesEnabled)
|
||||
{
|
||||
// Focus on this prefab
|
||||
m_prefabFocusPublicInterface->FocusOnOwningPrefab(entityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace AzToolsFramework
|
||||
|
||||
namespace Prefab
|
||||
{
|
||||
class PrefabFocusInterface;
|
||||
class PrefabFocusPublicInterface;
|
||||
class PrefabPublicInterface;
|
||||
};
|
||||
|
||||
@@ -29,16 +29,17 @@ namespace AzToolsFramework
|
||||
PrefabUiHandler();
|
||||
~PrefabUiHandler() override = default;
|
||||
|
||||
// EditorEntityUiHandler...
|
||||
// EditorEntityUiHandler overrides ...
|
||||
QString GenerateItemInfoString(AZ::EntityId entityId) const override;
|
||||
QString GenerateItemTooltip(AZ::EntityId entityId) const override;
|
||||
QIcon GenerateItemIcon(AZ::EntityId entityId) const override;
|
||||
void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
void PaintDescendantBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index,
|
||||
const QModelIndex& descendantIndex) const override;
|
||||
void OnDoubleClick(AZ::EntityId entityId) const override;
|
||||
|
||||
private:
|
||||
Prefab::PrefabFocusInterface* m_prefabFocusInterface = nullptr;
|
||||
Prefab::PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr;
|
||||
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
|
||||
static bool IsLastVisibleChild(const QModelIndex& parent, const QModelIndex& child);
|
||||
|
||||
+7
-7
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
@@ -31,8 +31,8 @@ namespace AzToolsFramework::Prefab
|
||||
void PrefabViewportFocusPathHandler::Initialize(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton)
|
||||
{
|
||||
// Get reference to the PrefabFocusInterface handler
|
||||
m_prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
|
||||
if (m_prefabFocusInterface == nullptr)
|
||||
m_prefabFocusPublicInterface = AZ::Interface<PrefabFocusPublicInterface>::Get();
|
||||
if (m_prefabFocusPublicInterface == nullptr)
|
||||
{
|
||||
AZ_Assert(false, "Prefab - could not get PrefabFocusInterface on PrefabViewportFocusPathHandler construction.");
|
||||
return;
|
||||
@@ -46,7 +46,7 @@ namespace AzToolsFramework::Prefab
|
||||
connect(m_breadcrumbsWidget, &AzQtComponents::BreadCrumbs::linkClicked, this,
|
||||
[&](const QString&, int linkIndex)
|
||||
{
|
||||
m_prefabFocusInterface->FocusOnPathIndex(m_editorEntityContextId, linkIndex);
|
||||
m_prefabFocusPublicInterface->FocusOnPathIndex(m_editorEntityContextId, linkIndex);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -54,9 +54,9 @@ namespace AzToolsFramework::Prefab
|
||||
connect(m_backButton, &QToolButton::clicked, this,
|
||||
[&]()
|
||||
{
|
||||
if (int length = m_prefabFocusInterface->GetPrefabFocusPathLength(m_editorEntityContextId); length > 1)
|
||||
if (int length = m_prefabFocusPublicInterface->GetPrefabFocusPathLength(m_editorEntityContextId); length > 1)
|
||||
{
|
||||
m_prefabFocusInterface->FocusOnPathIndex(m_editorEntityContextId, length - 2);
|
||||
m_prefabFocusPublicInterface->FocusOnPathIndex(m_editorEntityContextId, length - 2);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -65,7 +65,7 @@ namespace AzToolsFramework::Prefab
|
||||
void PrefabViewportFocusPathHandler::OnPrefabFocusChanged()
|
||||
{
|
||||
// Push new Path
|
||||
m_breadcrumbsWidget->pushPath(m_prefabFocusInterface->GetPrefabFocusPath(m_editorEntityContextId).c_str());
|
||||
m_breadcrumbsWidget->pushPath(m_prefabFocusPublicInterface->GetPrefabFocusPath(m_editorEntityContextId).c_str());
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
class PrefabFocusInterface;
|
||||
class PrefabFocusPublicInterface;
|
||||
|
||||
class PrefabViewportFocusPathHandler
|
||||
: public PrefabFocusNotificationBus::Handler
|
||||
@@ -40,6 +40,6 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
|
||||
PrefabFocusInterface* m_prefabFocusInterface = nullptr;
|
||||
PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr;
|
||||
};
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
|
||||
@@ -90,7 +90,6 @@ namespace AzToolsFramework
|
||||
|
||||
void SetComponentOverridden(const bool overridden);
|
||||
|
||||
// Calls match EditorComponentModeNotificationBus - called from EntityPropertyEditor
|
||||
void EnteredComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes);
|
||||
void LeftComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes);
|
||||
void ActiveComponentModeChanged(const AZ::Uuid& componentType);
|
||||
|
||||
+39
-24
@@ -33,6 +33,7 @@ AZ_POP_DISABLE_WARNING
|
||||
#include <AzQtComponents/Components/Style.h>
|
||||
#include <AzQtComponents/Components/Widgets/DragAndDrop.h>
|
||||
#include <AzQtComponents/Components/Widgets/LineEdit.h>
|
||||
#include <AzToolsFramework/API/ComponentModeCollectionInterface.h>
|
||||
#include <AzToolsFramework/API/EntityCompositionRequestBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
@@ -486,8 +487,12 @@ namespace AzToolsFramework
|
||||
, m_isSystemEntityEditor(false)
|
||||
, m_isLevelEntityEditor(isLevelEntityEditor)
|
||||
{
|
||||
|
||||
initEntityPropertyEditorResources();
|
||||
|
||||
m_componentModeCollection = AZ::Interface<ComponentModeCollectionInterface>::Get();
|
||||
AZ_Assert(m_componentModeCollection, "Could not retrieve component mode collection.");
|
||||
|
||||
m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
|
||||
AZ_Assert(m_prefabPublicInterface != nullptr, "EntityPropertyEditor requires a PrefabPublicInterface instance on Initialize.");
|
||||
|
||||
@@ -5698,39 +5703,49 @@ namespace AzToolsFramework
|
||||
SaveComponentEditorState();
|
||||
}
|
||||
|
||||
void EntityPropertyEditor::EnteredComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes)
|
||||
void EntityPropertyEditor::OnEditorModeActivated(
|
||||
[[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode)
|
||||
{
|
||||
DisableComponentActions(this, m_entityComponentActions);
|
||||
SetPropertyEditorState(m_gui, false);
|
||||
m_disabled = true;
|
||||
|
||||
if (!componentModeTypes.empty())
|
||||
if (mode == AzToolsFramework::ViewportEditorMode::Component)
|
||||
{
|
||||
m_componentEditorLastSelectedIndex = GetComponentEditorIndexFromType(componentModeTypes.front());
|
||||
}
|
||||
DisableComponentActions(this, m_entityComponentActions);
|
||||
SetPropertyEditorState(m_gui, false);
|
||||
const auto componentModeTypes = m_componentModeCollection->GetComponentTypes();
|
||||
m_disabled = true;
|
||||
|
||||
if (!componentModeTypes.empty())
|
||||
{
|
||||
m_componentEditorLastSelectedIndex = GetComponentEditorIndexFromType(componentModeTypes.front());
|
||||
}
|
||||
|
||||
for (auto componentEditor : m_componentEditors)
|
||||
{
|
||||
componentEditor->EnteredComponentMode(componentModeTypes);
|
||||
}
|
||||
for (auto componentEditor : m_componentEditors)
|
||||
{
|
||||
componentEditor->EnteredComponentMode(componentModeTypes);
|
||||
}
|
||||
|
||||
// record the selected state after entering component mode
|
||||
SaveComponentEditorState();
|
||||
// record the selected state after entering component mode
|
||||
SaveComponentEditorState();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityPropertyEditor::LeftComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes)
|
||||
void EntityPropertyEditor::OnEditorModeDeactivated(
|
||||
[[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode)
|
||||
{
|
||||
EnableComponentActions(this, m_entityComponentActions);
|
||||
SetPropertyEditorState(m_gui, true);
|
||||
m_disabled = false;
|
||||
|
||||
for (auto componentEditor : m_componentEditors)
|
||||
if (mode == AzToolsFramework::ViewportEditorMode::Component)
|
||||
{
|
||||
componentEditor->LeftComponentMode(componentModeTypes);
|
||||
}
|
||||
EnableComponentActions(this, m_entityComponentActions);
|
||||
SetPropertyEditorState(m_gui, true);
|
||||
const auto componentModeTypes = m_componentModeCollection->GetComponentTypes();
|
||||
m_disabled = false;
|
||||
|
||||
// record the selected state after leaving component mode
|
||||
SaveComponentEditorState();
|
||||
for (auto componentEditor : m_componentEditors)
|
||||
{
|
||||
componentEditor->LeftComponentMode(componentModeTypes);
|
||||
}
|
||||
|
||||
// record the selected state after leaving component mode
|
||||
SaveComponentEditorState();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityPropertyEditor::ActiveComponentModeChanged(const AZ::Uuid& componentType)
|
||||
|
||||
+11
-2
@@ -26,6 +26,7 @@
|
||||
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/API/EntityPropertyEditorRequestsBus.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
|
||||
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/ComponentMimeData.h>
|
||||
@@ -59,6 +60,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
class ComponentEditor;
|
||||
class ComponentPaletteWidget;
|
||||
class ComponentModeCollectionInterface;
|
||||
struct SourceControlFileInfo;
|
||||
|
||||
namespace AssetBrowser
|
||||
@@ -108,6 +110,7 @@ namespace AzToolsFramework
|
||||
, public AzToolsFramework::EditorEntityContextNotificationBus::Handler
|
||||
, public AzToolsFramework::EntityPropertyEditorRequestBus::Handler
|
||||
, public AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler
|
||||
, private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler
|
||||
, public EditorInspectorComponentNotificationBus::MultiHandler
|
||||
, private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler
|
||||
, public AZ::EntitySystemBus::Handler
|
||||
@@ -231,10 +234,14 @@ namespace AzToolsFramework
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// EditorComponentModeNotificationBus
|
||||
void EnteredComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes) override;
|
||||
void LeftComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes) override;
|
||||
void ActiveComponentModeChanged(const AZ::Uuid& componentType) override;
|
||||
|
||||
// ViewportEditorModeNotificationsBus overrides ...
|
||||
void OnEditorModeActivated(
|
||||
const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override;
|
||||
void OnEditorModeDeactivated(
|
||||
const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override;
|
||||
|
||||
// EntityPropertEditorRequestBus
|
||||
void GetSelectedAndPinnedEntities(EntityIdList& selectedEntityIds) override;
|
||||
void GetSelectedEntities(EntityIdList& selectedEntityIds) override;
|
||||
@@ -627,6 +634,8 @@ namespace AzToolsFramework
|
||||
float m_moveFadeSecondsRemaining;
|
||||
AZStd::vector<int> m_indexMapOfMovedRow;
|
||||
|
||||
AzToolsFramework::ComponentModeCollectionInterface* m_componentModeCollection = nullptr;
|
||||
|
||||
// When m_initiatingPropertyChangeNotification is set to true, it means this EntityPropertyEditor is
|
||||
// broadcasting a change to all listeners about a property change for a given entity. This is needed
|
||||
// so that we don't update the values twice for this inspector
|
||||
|
||||
+53
-4
@@ -28,6 +28,9 @@ AZ_PUSH_DISABLE_WARNING(4244 4251, "-Wunknown-warning-option")
|
||||
#include <QTableView>
|
||||
#include <QHeaderView>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QByteArray>
|
||||
#include <QDataStream>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
@@ -1230,6 +1233,16 @@ namespace AzToolsFramework
|
||||
return m_showThumbnailDropDownButton;
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetCustomThumbnailEnabled(bool enabled)
|
||||
{
|
||||
m_thumbnail->SetCustomThumbnailEnabled(enabled);
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetCustomThumbnailPixmap(const QPixmap& pixmap)
|
||||
{
|
||||
m_thumbnail->SetCustomThumbnailPixmap(pixmap);
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetThumbnailCallback(EditCallbackType* editNotifyCallback)
|
||||
{
|
||||
m_thumbnailCallback = editNotifyCallback;
|
||||
@@ -1356,15 +1369,27 @@ namespace AzToolsFramework
|
||||
GUI->SetClearNotifyCallback(nullptr);
|
||||
}
|
||||
}
|
||||
else if (attrib == AZ_CRC("BrowseIcon", 0x507d7a4f))
|
||||
else if (attrib == AZ_CRC_CE("BrowseIcon"))
|
||||
{
|
||||
AZStd::string iconPath;
|
||||
attrValue->Read<AZStd::string>(iconPath);
|
||||
|
||||
if (!iconPath.empty())
|
||||
if (attrValue->Read<AZStd::string>(iconPath) && !iconPath.empty())
|
||||
{
|
||||
GUI->SetBrowseButtonIcon(QIcon(iconPath.c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// A QPixmap object can't be assigned directly via an attribute.
|
||||
// This allows dynamic icon data to be supplied as a buffer containing a serialized QPixmap.
|
||||
AZStd::vector<char> pixmapBuffer;
|
||||
if (attrValue->Read<AZStd::vector<char>>(pixmapBuffer) && !pixmapBuffer.empty())
|
||||
{
|
||||
QByteArray pixmapBytes(pixmapBuffer.data(), aznumeric_cast<int>(pixmapBuffer.size()));
|
||||
QDataStream stream(&pixmapBytes, QIODevice::ReadOnly);
|
||||
QPixmap pixmap;
|
||||
stream >> pixmap;
|
||||
GUI->SetBrowseButtonIcon(pixmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attrib == AZ_CRC_CE("BrowseButtonEnabled"))
|
||||
{
|
||||
@@ -1390,6 +1415,30 @@ namespace AzToolsFramework
|
||||
GUI->SetShowThumbnail(showThumbnail);
|
||||
}
|
||||
}
|
||||
else if (attrib == AZ_CRC_CE("ThumbnailIcon"))
|
||||
{
|
||||
AZStd::string iconPath;
|
||||
if (attrValue->Read<AZStd::string>(iconPath) && !iconPath.empty())
|
||||
{
|
||||
GUI->SetCustomThumbnailEnabled(true);
|
||||
GUI->SetCustomThumbnailPixmap(QPixmap::fromImage(QImage(iconPath.c_str())));
|
||||
}
|
||||
else
|
||||
{
|
||||
// A QPixmap object can't be assigned directly via an attribute.
|
||||
// This allows dynamic icon data to be supplied as a buffer containing a serialized QPixmap.
|
||||
AZStd::vector<char> pixmapBuffer;
|
||||
if (attrValue->Read<AZStd::vector<char>>(pixmapBuffer) && !pixmapBuffer.empty())
|
||||
{
|
||||
QByteArray pixmapBytes(pixmapBuffer.data(), aznumeric_cast<int>(pixmapBuffer.size()));
|
||||
QDataStream stream(&pixmapBytes, QIODevice::ReadOnly);
|
||||
QPixmap pixmap;
|
||||
stream >> pixmap;
|
||||
GUI->SetCustomThumbnailEnabled(true);
|
||||
GUI->SetCustomThumbnailPixmap(pixmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attrib == AZ_CRC_CE("ThumbnailCallback"))
|
||||
{
|
||||
PropertyAssetCtrl::EditCallbackType* func = azdynamic_cast<PropertyAssetCtrl::EditCallbackType*>(attrValue->GetAttribute());
|
||||
|
||||
+5
@@ -217,12 +217,17 @@ namespace AzToolsFramework
|
||||
void SetHideProductFilesInAssetPicker(bool hide);
|
||||
bool GetHideProductFilesInAssetPicker() const;
|
||||
|
||||
// Enable and configure a thumbnail widget that displays an asset preview and dropdown arrow for a dropdown menu
|
||||
void SetShowThumbnail(bool enable);
|
||||
bool GetShowThumbnail() const;
|
||||
void SetShowThumbnailDropDownButton(bool enable);
|
||||
bool GetShowThumbnailDropDownButton() const;
|
||||
void SetThumbnailCallback(EditCallbackType* editNotifyCallback);
|
||||
|
||||
// If enabled, replaces the thumbnail widget content with a custom pixmap
|
||||
void SetCustomThumbnailEnabled(bool enabled);
|
||||
void SetCustomThumbnailPixmap(const QPixmap& pixmap);
|
||||
|
||||
void SetSelectedAssetID(const AZ::Data::AssetId& newID);
|
||||
void SetCurrentAssetType(const AZ::Data::AssetType& newType);
|
||||
void SetSelectedAssetID(const AZ::Data::AssetId& newID, const AZ::Data::AssetType& newType);
|
||||
|
||||
+2
-3
@@ -38,7 +38,7 @@ namespace AzToolsFramework
|
||||
static bool UnsignedToolTip(QWidget* widget, QString& toolTipString);
|
||||
};
|
||||
|
||||
//! Base class for integer widget handlers to provide functionality independant
|
||||
//! Base class for integer widget handlers to provide functionality independent
|
||||
//! of widget type.
|
||||
//! @tparam ValueType The integer primitive type of the handler.
|
||||
//! @tparam PropertyControl The widget type of the handler.
|
||||
@@ -167,8 +167,7 @@ namespace AzToolsFramework
|
||||
PropertyControl* newCtrl = aznew PropertyControl(pParent);
|
||||
this->connect(newCtrl, &PropertyControl::valueChanged, this, [newCtrl]()
|
||||
{
|
||||
EBUS_EVENT(PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl);
|
||||
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&PropertyEditorGUIMessages::Bus::Handler::RequestWrite, newCtrl);
|
||||
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&PropertyEditorGUIMessages::Bus::Events::RequestWrite, newCtrl);
|
||||
});
|
||||
// note: Qt automatically disconnects objects from each other when either end is destroyed, no need to worry about delete.
|
||||
|
||||
|
||||
-5
@@ -98,11 +98,6 @@ namespace AzToolsFramework
|
||||
QWidget* IntSpinBoxHandler<ValueType>::CreateGUI(QWidget* parent)
|
||||
{
|
||||
PropertyIntSpinCtrl* newCtrl = static_cast<PropertyIntSpinCtrl*>(BaseHandler::CreateGUI(parent));
|
||||
this->connect(newCtrl, &PropertyIntSpinCtrl::valueChanged, [newCtrl]()
|
||||
{
|
||||
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&PropertyEditorGUIMessages::Bus::Handler::RequestWrite, newCtrl);
|
||||
});
|
||||
|
||||
return newCtrl;
|
||||
}
|
||||
|
||||
|
||||
+3
-10
@@ -1102,10 +1102,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
m_dropDownArrow->hide();
|
||||
}
|
||||
m_indent->changeSize((m_treeDepth * m_treeIndentation) + m_leafIndentation, 1, QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
m_leftHandSideLayout->invalidate();
|
||||
m_leftHandSideLayout->update();
|
||||
m_leftHandSideLayout->activate();
|
||||
SetIndentSize(m_treeDepth * m_treeIndentation + m_leafIndentation);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1117,10 +1114,7 @@ namespace AzToolsFramework
|
||||
connect(m_dropDownArrow, &QCheckBox::clicked, this, &PropertyRowWidget::OnClickedExpansionButton);
|
||||
}
|
||||
m_dropDownArrow->show();
|
||||
m_indent->changeSize((m_treeDepth * m_treeIndentation), 1, QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
m_leftHandSideLayout->invalidate();
|
||||
m_leftHandSideLayout->update();
|
||||
m_leftHandSideLayout->activate();
|
||||
SetIndentSize(m_treeDepth * m_treeIndentation);
|
||||
m_dropDownArrow->setChecked(m_expanded);
|
||||
}
|
||||
}
|
||||
@@ -1720,10 +1714,9 @@ namespace AzToolsFramework
|
||||
}
|
||||
else
|
||||
{
|
||||
m_indicatorButton->setVisible(true);
|
||||
|
||||
QPixmap pixmap(imagePath);
|
||||
m_indicatorButton->setIcon(pixmap);
|
||||
m_indicatorButton->setVisible(true);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/PropertyEditor/Resources">
|
||||
<file>blank.png</file>
|
||||
<file>point_hand.png</file>
|
||||
<file>cross-circle-small.png</file>
|
||||
<file>cross-small.png</file>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:81b5fa1f978888c3be8a40fce20455668df2723a77587aeb7039f8bf74bdd0e3
|
||||
size 119
|
||||
+84
-47
@@ -7,75 +7,117 @@
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Debug/TraceContext.h>
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: 'QRawFont::d': class 'QExplicitlySharedDataPointer<QRawFontPrivate>' needs to have dll-interface to be used by clients of class 'QRawFont'
|
||||
// 4800: 'QTextEngine *const ': forcing value to bool 'true' or 'false' (performance warning)
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
#include <UI/UICore/AspectRatioAwarePixmapWidget.hxx>
|
||||
#include <Thumbnails/ThumbnailWidget.h>
|
||||
|
||||
// 4251: 'QRawFont::d': class 'QExplicitlySharedDataPointer<QRawFontPrivate>' needs to have dll-interface to be used by clients of class
|
||||
// 'QRawFont' 4800: 'QTextEngine *const ': forcing value to bool 'true' or 'false' (performance warning)
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option")
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPainter>
|
||||
#include <Thumbnails/ThumbnailWidget.h>
|
||||
#include <UI/UICore/AspectRatioAwarePixmapWidget.hxx>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
#include "ThumbnailPropertyCtrl.h"
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
|
||||
ThumbnailPropertyCtrl::ThumbnailPropertyCtrl(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QHBoxLayout* pLayout = new QHBoxLayout();
|
||||
pLayout->setContentsMargins(0, 0, 0, 0);
|
||||
pLayout->setSpacing(0);
|
||||
|
||||
m_thumbnail = new Thumbnailer::ThumbnailWidget(this);
|
||||
m_thumbnail->setFixedSize(QSize(24, 24));
|
||||
|
||||
m_thumbnailEnlarged = new Thumbnailer::ThumbnailWidget(this);
|
||||
m_thumbnailEnlarged->setFixedSize(QSize(180, 180));
|
||||
m_thumbnailEnlarged->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
|
||||
|
||||
m_customThumbnail = new QLabel(this);
|
||||
m_customThumbnail->setFixedSize(QSize(24, 24));
|
||||
m_customThumbnail->setScaledContents(true);
|
||||
|
||||
m_customThumbnailEnlarged = new QLabel(this);
|
||||
m_customThumbnailEnlarged->setFixedSize(QSize(180, 180));
|
||||
m_customThumbnailEnlarged->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
|
||||
m_customThumbnailEnlarged->setScaledContents(true);
|
||||
|
||||
m_dropDownArrow = new AspectRatioAwarePixmapWidget(this);
|
||||
m_dropDownArrow->setPixmap(QPixmap(":/stylesheet/img/triangle0.png"));
|
||||
m_dropDownArrow->setFixedSize(QSize(8, 24));
|
||||
ShowDropDownArrow(false);
|
||||
|
||||
m_emptyThumbnail = new QLabel(this);
|
||||
m_emptyThumbnail->setPixmap(QPixmap(":/stylesheet/img/line.png"));
|
||||
m_emptyThumbnail->setFixedSize(QSize(24, 24));
|
||||
|
||||
pLayout->addWidget(m_emptyThumbnail);
|
||||
QHBoxLayout* pLayout = new QHBoxLayout();
|
||||
pLayout->setContentsMargins(0, 0, 0, 0);
|
||||
pLayout->setSpacing(0);
|
||||
pLayout->addWidget(m_thumbnail);
|
||||
pLayout->addWidget(m_customThumbnail);
|
||||
pLayout->addWidget(m_emptyThumbnail);
|
||||
pLayout->addSpacing(4);
|
||||
pLayout->addWidget(m_dropDownArrow);
|
||||
pLayout->addSpacing(4);
|
||||
|
||||
setLayout(pLayout);
|
||||
|
||||
ShowDropDownArrow(false);
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void ThumbnailPropertyCtrl::SetThumbnailKey(Thumbnailer::SharedThumbnailKey key, const char* contextName)
|
||||
{
|
||||
m_key = key;
|
||||
m_emptyThumbnail->setVisible(false);
|
||||
m_thumbnail->SetThumbnailKey(key, contextName);
|
||||
if (m_customThumbnailEnabled)
|
||||
{
|
||||
ClearThumbnail();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_key = key;
|
||||
m_thumbnail->SetThumbnailKey(m_key, contextName);
|
||||
m_thumbnailEnlarged->SetThumbnailKey(m_key, contextName);
|
||||
}
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void ThumbnailPropertyCtrl::ClearThumbnail()
|
||||
{
|
||||
m_emptyThumbnail->setVisible(true);
|
||||
m_key.clear();
|
||||
m_thumbnail->ClearThumbnail();
|
||||
m_thumbnailEnlarged->ClearThumbnail();
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void ThumbnailPropertyCtrl::ShowDropDownArrow(bool visible)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
setFixedSize(QSize(40, 24));
|
||||
}
|
||||
else
|
||||
{
|
||||
setFixedSize(QSize(24, 24));
|
||||
}
|
||||
setFixedSize(QSize(visible ? 40 : 24, 24));
|
||||
m_dropDownArrow->setVisible(visible);
|
||||
}
|
||||
|
||||
void ThumbnailPropertyCtrl::SetCustomThumbnailEnabled(bool enabled)
|
||||
{
|
||||
m_customThumbnailEnabled = enabled;
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void ThumbnailPropertyCtrl::SetCustomThumbnailPixmap(const QPixmap& pixmap)
|
||||
{
|
||||
m_customThumbnail->setPixmap(pixmap);
|
||||
m_customThumbnailEnlarged->setPixmap(pixmap);
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void ThumbnailPropertyCtrl::UpdateVisibility()
|
||||
{
|
||||
m_thumbnail->setVisible(m_key && !m_customThumbnailEnabled);
|
||||
m_thumbnailEnlarged->setVisible(false);
|
||||
|
||||
m_customThumbnail->setVisible(m_customThumbnailEnabled);
|
||||
m_customThumbnailEnlarged->setVisible(false);
|
||||
|
||||
m_emptyThumbnail->setVisible(!m_key && !m_customThumbnailEnabled);
|
||||
}
|
||||
|
||||
bool ThumbnailPropertyCtrl::event(QEvent* e)
|
||||
{
|
||||
if (isEnabled())
|
||||
@@ -83,7 +125,7 @@ namespace AzToolsFramework
|
||||
if (e->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
emit clicked();
|
||||
return true; //ignore
|
||||
return true; // ignore
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,37 +136,32 @@ namespace AzToolsFramework
|
||||
{
|
||||
QPainter p(this);
|
||||
QRect targetRect(QPoint(), QSize(40, 24));
|
||||
p.fillRect(targetRect, QColor(17, 17, 17)); // #111111
|
||||
p.fillRect(targetRect, QColor("#111111"));
|
||||
QWidget::paintEvent(e);
|
||||
}
|
||||
|
||||
void ThumbnailPropertyCtrl::enterEvent(QEvent* e)
|
||||
{
|
||||
m_dropDownArrow->setPixmap(QPixmap(":/stylesheet/img/triangle0_highlighted.png"));
|
||||
if (!m_thumbnailEnlarged && m_key)
|
||||
{
|
||||
QPoint position = mapToGlobal(pos() - QPoint(185, 0));
|
||||
QSize size(180, 180);
|
||||
m_thumbnailEnlarged.reset(new Thumbnailer::ThumbnailWidget());
|
||||
m_thumbnailEnlarged->setFixedSize(size);
|
||||
m_thumbnailEnlarged->move(position);
|
||||
m_thumbnailEnlarged->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
|
||||
m_thumbnailEnlarged->SetThumbnailKey(m_key);
|
||||
m_thumbnailEnlarged->raise();
|
||||
m_thumbnailEnlarged->show();
|
||||
}
|
||||
const QPoint offset(-m_thumbnailEnlarged->width() - 5, -m_thumbnailEnlarged->height() / 2 + m_thumbnail->height() / 2);
|
||||
|
||||
m_thumbnailEnlarged->move(mapToGlobal(pos()) + offset);
|
||||
m_thumbnailEnlarged->raise();
|
||||
m_thumbnailEnlarged->setVisible(m_key && !m_customThumbnailEnabled);
|
||||
|
||||
m_customThumbnailEnlarged->move(mapToGlobal(pos()) + offset);
|
||||
m_customThumbnailEnlarged->raise();
|
||||
m_customThumbnailEnlarged->setVisible(m_customThumbnailEnabled);
|
||||
QWidget::enterEvent(e);
|
||||
}
|
||||
|
||||
void ThumbnailPropertyCtrl::leaveEvent(QEvent* e)
|
||||
{
|
||||
m_dropDownArrow->setPixmap(QPixmap(":/stylesheet/img/triangle0.png"));
|
||||
if (m_thumbnailEnlarged)
|
||||
{
|
||||
m_thumbnailEnlarged.reset();
|
||||
}
|
||||
m_thumbnailEnlarged->setVisible(false);
|
||||
m_customThumbnailEnlarged->setVisible(false);
|
||||
QWidget::leaveEvent(e);
|
||||
}
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
#include "UI/PropertyEditor/moc_ThumbnailPropertyCtrl.cpp"
|
||||
|
||||
+19
-6
@@ -1,5 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@@ -8,6 +6,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/PlatformDef.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
@@ -35,25 +35,38 @@ namespace AzToolsFramework
|
||||
|
||||
//! Call this to set what thumbnail widget will display
|
||||
void SetThumbnailKey(Thumbnailer::SharedThumbnailKey key, const char* contextName = "Default");
|
||||
|
||||
//! Remove current thumbnail
|
||||
void ClearThumbnail();
|
||||
|
||||
//! Display a clickable dropdown arrow next to the thumbnail
|
||||
void ShowDropDownArrow(bool visible);
|
||||
|
||||
bool event(QEvent* e) override;
|
||||
//! Override the thumbnail widget with a custom image
|
||||
void SetCustomThumbnailEnabled(bool enabled);
|
||||
|
||||
//! Assign a custom image to display in place of thumbnail
|
||||
void SetCustomThumbnailPixmap(const QPixmap& pixmap);
|
||||
|
||||
Q_SIGNALS:
|
||||
void clicked();
|
||||
|
||||
protected:
|
||||
private:
|
||||
void UpdateVisibility();
|
||||
|
||||
bool event(QEvent* e) override;
|
||||
void paintEvent(QPaintEvent* e) override;
|
||||
void enterEvent(QEvent* e) override;
|
||||
void leaveEvent(QEvent* e) override;
|
||||
|
||||
private:
|
||||
Thumbnailer::SharedThumbnailKey m_key;
|
||||
Thumbnailer::ThumbnailWidget* m_thumbnail = nullptr;
|
||||
QScopedPointer<Thumbnailer::ThumbnailWidget> m_thumbnailEnlarged;
|
||||
Thumbnailer::ThumbnailWidget* m_thumbnailEnlarged = nullptr;
|
||||
|
||||
QLabel* m_customThumbnail = nullptr;
|
||||
QLabel* m_customThumbnailEnlarged = nullptr;
|
||||
bool m_customThumbnailEnabled = false;
|
||||
|
||||
QLabel* m_emptyThumbnail = nullptr;
|
||||
AspectRatioAwarePixmapWidget* m_dropDownArrow = nullptr;
|
||||
};
|
||||
|
||||
+14
-6
@@ -129,7 +129,7 @@ namespace UnitTest
|
||||
using AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus;
|
||||
|
||||
AzToolsFramework::EditorActionRequestBus::Handler::BusConnect();
|
||||
EditorComponentModeNotificationBus::Handler::BusConnect(GetEntityContextId());
|
||||
ViewportEditorModeNotificationsBus::Handler::BusConnect(GetEntityContextId());
|
||||
m_defaultWidget.setFocus();
|
||||
}
|
||||
|
||||
@@ -137,18 +137,26 @@ namespace UnitTest
|
||||
{
|
||||
using AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus;
|
||||
|
||||
EditorComponentModeNotificationBus::Handler::BusDisconnect();
|
||||
ViewportEditorModeNotificationsBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorActionRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void TestEditorActions::EnteredComponentMode([[maybe_unused]] const AZStd::vector<AZ::Uuid>& componentTypes)
|
||||
void TestEditorActions::OnEditorModeActivated(
|
||||
[[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode)
|
||||
{
|
||||
m_componentModeWidget.setFocus();
|
||||
if (mode == ViewportEditorMode::Component)
|
||||
{
|
||||
m_componentModeWidget.setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void TestEditorActions::LeftComponentMode([[maybe_unused]] const AZStd::vector<AZ::Uuid>& componentTypes)
|
||||
void TestEditorActions::OnEditorModeDeactivated(
|
||||
[[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode)
|
||||
{
|
||||
m_defaultWidget.setFocus();
|
||||
if (mode == ViewportEditorMode::Component)
|
||||
{
|
||||
m_defaultWidget.setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void TestEditorActions::AddActionViaBus(int id, QAction* action)
|
||||
|
||||
+7
-5
@@ -23,9 +23,9 @@
|
||||
#include <AZTestShared/Utils/Utils.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerInterface.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityTransformBus.h>
|
||||
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
|
||||
#include <AzToolsFramework/Viewport/ActionBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
@@ -103,7 +103,7 @@ namespace UnitTest
|
||||
/// component mode editing.
|
||||
class TestEditorActions
|
||||
: private AzToolsFramework::EditorActionRequestBus::Handler
|
||||
, private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler
|
||||
, private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler
|
||||
{
|
||||
// EditorActionRequestBus ...
|
||||
void AddActionViaBus(int id, QAction* action) override;
|
||||
@@ -114,9 +114,11 @@ namespace UnitTest
|
||||
void AttachOverride(QWidget* /*object*/) override {}
|
||||
void DetachOverride() override {}
|
||||
|
||||
// EditorComponentModeNotificationBus ...
|
||||
void EnteredComponentMode(const AZStd::vector<AZ::Uuid>& componentTypes) override;
|
||||
void LeftComponentMode(const AZStd::vector<AZ::Uuid>& componentTypes) override;
|
||||
// ViewportEditorModeNotificationsBus overrides ...
|
||||
void OnEditorModeActivated(
|
||||
const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override;
|
||||
void OnEditorModeDeactivated(
|
||||
const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override;
|
||||
|
||||
public:
|
||||
void Connect();
|
||||
|
||||
+11
-2
@@ -27,19 +27,28 @@ namespace AzToolsFramework
|
||||
, m_viewportEditorModeTracker(viewportEditorModeTracker)
|
||||
, m_componentModeCollection(viewportEditorModeTracker)
|
||||
{
|
||||
AZ_Assert(
|
||||
AZ::Interface<ComponentModeCollectionInterface>::Get() == nullptr, "Unexpected registration of component mode collection.")
|
||||
AZ::Interface<ComponentModeCollectionInterface>::Register(&m_componentModeCollection);
|
||||
|
||||
ActionOverrideRequestBus::Handler::BusConnect(GetEntityContextId());
|
||||
ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusConnect();
|
||||
|
||||
m_manipulatorManager = AZStd::make_shared<AzToolsFramework::ManipulatorManager>(AzToolsFramework::g_mainManipulatorManagerId);
|
||||
m_transformComponentSelection = AZStd::make_unique<EditorTransformComponentSelection>(entityDataCache);
|
||||
m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default);
|
||||
m_viewportEditorModeTracker->ActivateMode({ GetEntityContextId() }, ViewportEditorMode::Default);
|
||||
}
|
||||
|
||||
EditorDefaultSelection::~EditorDefaultSelection()
|
||||
{
|
||||
ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusDisconnect();
|
||||
ActionOverrideRequestBus::Handler::BusDisconnect();
|
||||
m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default);
|
||||
m_viewportEditorModeTracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Default);
|
||||
|
||||
AZ_Assert(
|
||||
AZ::Interface<ComponentModeCollectionInterface>::Get() != nullptr,
|
||||
"Unexpected unregistration of component mode collection.")
|
||||
AZ::Interface<ComponentModeCollectionInterface>::Unregister(&m_componentModeCollection);
|
||||
}
|
||||
|
||||
void EditorDefaultSelection::SetOverridePhantomWidget(QWidget* phantomOverrideWidget)
|
||||
|
||||
+31
-3
@@ -13,8 +13,9 @@
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AzFramework/Viewport/ViewportScreen.h>
|
||||
#include <AzFramework/Visibility/BoundsBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/API/EditorViewportIconDisplayInterface.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorEntityIconComponentBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
@@ -186,11 +187,18 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
// Verify if the entity Id corresponds to an entity that is focused; if not, halt selection.
|
||||
if (!m_focusModeInterface->IsInFocusSubTree(entityIdUnderCursor))
|
||||
if (!IsSelectableAccordingToFocusMode(entityIdUnderCursor))
|
||||
{
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
// Container Entity support - if the entity that is being selected is part of a closed container,
|
||||
// change the selection to the container instead.
|
||||
if (ContainerEntityInterface* containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get())
|
||||
{
|
||||
return containerEntityInterface->FindHighestSelectableEntity(entityIdUnderCursor);
|
||||
}
|
||||
|
||||
return entityIdUnderCursor;
|
||||
}
|
||||
|
||||
@@ -208,7 +216,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex);
|
||||
|
||||
if (!m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex))
|
||||
if (!m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex) || !IsSelectableInViewport(entityId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -254,4 +262,24 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorHelpers::IsSelectableInViewport(AZ::EntityId entityId)
|
||||
{
|
||||
return IsSelectableAccordingToFocusMode(entityId) && IsSelectableAccordingToContainerEntities(entityId);
|
||||
}
|
||||
|
||||
bool EditorHelpers::IsSelectableAccordingToFocusMode(AZ::EntityId entityId)
|
||||
{
|
||||
return m_focusModeInterface->IsInFocusSubTree(entityId);
|
||||
}
|
||||
|
||||
bool EditorHelpers::IsSelectableAccordingToContainerEntities(AZ::EntityId entityId)
|
||||
{
|
||||
if (ContainerEntityInterface* containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get())
|
||||
{
|
||||
return !containerEntityInterface->IsUnderClosedContainerEntity(entityId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -58,7 +58,19 @@ namespace AzToolsFramework
|
||||
AzFramework::DebugDisplayRequests& debugDisplay,
|
||||
const AZStd::function<bool(AZ::EntityId)>& showIconCheck);
|
||||
|
||||
//! Returns whether the entityId can be selected in the viewport according
|
||||
//! to the current Editor Focus Mode and Container Entity setup.
|
||||
bool IsSelectableInViewport(AZ::EntityId entityId);
|
||||
|
||||
private:
|
||||
//! Returns whether the entityId can be selected in the viewport according
|
||||
//! to the current Editor Focus Mode setup.
|
||||
bool IsSelectableAccordingToFocusMode(AZ::EntityId entityId);
|
||||
|
||||
//! Returns whether the entityId can be selected in the viewport according
|
||||
//! to the current Container Entityu setup.
|
||||
bool IsSelectableAccordingToContainerEntities(AZ::EntityId entityId);
|
||||
|
||||
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers.
|
||||
const FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
};
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ namespace AzToolsFramework
|
||||
: m_editorHelpers(AZStd::make_unique<EditorHelpers>(entityDataCache))
|
||||
, m_viewportEditorModeTracker(viewportEditorModeTracker)
|
||||
{
|
||||
m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick);
|
||||
m_viewportEditorModeTracker->ActivateMode({ GetEntityContextId() }, ViewportEditorMode::Pick);
|
||||
}
|
||||
|
||||
EditorPickEntitySelection::~EditorPickEntitySelection()
|
||||
@@ -31,7 +31,7 @@ namespace AzToolsFramework
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, m_hoveredEntityId, false);
|
||||
}
|
||||
|
||||
m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick);
|
||||
m_viewportEditorModeTracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Pick);
|
||||
}
|
||||
|
||||
// note: entityIdUnderCursor is the authoritative entityId we get each frame by querying
|
||||
|
||||
+39
-78
@@ -103,10 +103,6 @@ namespace AzToolsFramework
|
||||
static const char* const ResetEntityTransformDesc = "Reset transform based on manipulator mode";
|
||||
static const char* const ResetManipulatorTitle = "Reset Manipulator";
|
||||
static const char* const ResetManipulatorDesc = "Reset the manipulator to recenter it on the selected entity";
|
||||
static const char* const ResetTransformLocalTitle = "Reset Transform (Local)";
|
||||
static const char* const ResetTransformLocalDesc = "Reset transform to local space";
|
||||
static const char* const ResetTransformWorldTitle = "Reset Transform (World)";
|
||||
static const char* const ResetTransformWorldDesc = "Reset transform to world space";
|
||||
|
||||
static const char* const EntityBoxSelectUndoRedoDesc = "Box Select Entities";
|
||||
static const char* const EntityDeselectUndoRedoDesc = "Deselect Entity";
|
||||
@@ -1027,7 +1023,7 @@ namespace AzToolsFramework
|
||||
EditorTransformComponentSelectionRequestBus::Handler::BusConnect(entityContextId);
|
||||
ToolsApplicationNotificationBus::Handler::BusConnect();
|
||||
Camera::EditorCameraNotificationBus::Handler::BusConnect();
|
||||
ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect(entityContextId);
|
||||
ViewportEditorModeNotificationsBus::Handler::BusConnect(entityContextId);
|
||||
EditorEntityContextNotificationBus::Handler::BusConnect();
|
||||
EditorEntityVisibilityNotificationBus::Router::BusRouterConnect();
|
||||
EditorEntityLockComponentNotificationBus::Router::BusRouterConnect();
|
||||
@@ -1075,7 +1071,7 @@ namespace AzToolsFramework
|
||||
EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect();
|
||||
EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect();
|
||||
EditorEntityContextNotificationBus::Handler::BusDisconnect();
|
||||
ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect();
|
||||
ViewportEditorModeNotificationsBus::Handler::BusDisconnect();
|
||||
Camera::EditorCameraNotificationBus::Handler::BusDisconnect();
|
||||
ToolsApplicationNotificationBus::Handler::BusDisconnect();
|
||||
EditorTransformComponentSelectionRequestBus::Handler::BusDisconnect();
|
||||
@@ -1117,7 +1113,7 @@ namespace AzToolsFramework
|
||||
});
|
||||
|
||||
m_boxSelect.InstallLeftMouseUp(
|
||||
[this, entityBoxSelectData]()
|
||||
[this, entityBoxSelectData]
|
||||
{
|
||||
entityBoxSelectData->m_boxSelectSelectionCommand->UpdateSelection(EntityIdVectorFromContainer(m_selectedEntityIds));
|
||||
|
||||
@@ -2175,7 +2171,7 @@ namespace AzToolsFramework
|
||||
// lock selection
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::Key_L) }, LockSelection, LockSelectionTitle, LockSelectionDesc,
|
||||
[lockUnlock]()
|
||||
[lockUnlock]
|
||||
{
|
||||
lockUnlock(true);
|
||||
});
|
||||
@@ -2183,7 +2179,7 @@ namespace AzToolsFramework
|
||||
// unlock selection
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::CTRL + Qt::Key_L) }, UnlockSelection, LockSelectionTitle, LockSelectionDesc,
|
||||
[lockUnlock]()
|
||||
[lockUnlock]
|
||||
{
|
||||
lockUnlock(false);
|
||||
});
|
||||
@@ -2213,7 +2209,7 @@ namespace AzToolsFramework
|
||||
// hide selection
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::Key_H) }, HideSelection, HideSelectionTitle, HideSelectionDesc,
|
||||
[showHide]()
|
||||
[showHide]
|
||||
{
|
||||
showHide(false);
|
||||
});
|
||||
@@ -2221,7 +2217,7 @@ namespace AzToolsFramework
|
||||
// show selection
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::CTRL + Qt::Key_H) }, ShowSelection, HideSelectionTitle, HideSelectionDesc,
|
||||
[showHide]()
|
||||
[showHide]
|
||||
{
|
||||
showHide(true);
|
||||
});
|
||||
@@ -2229,7 +2225,7 @@ namespace AzToolsFramework
|
||||
// unlock all entities in the level/scene
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_L) }, UnlockAll, UnlockAllTitle, UnlockAllDesc,
|
||||
[]()
|
||||
[]
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
@@ -2246,14 +2242,14 @@ namespace AzToolsFramework
|
||||
// show all entities in the level/scene
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_H) }, ShowAll, ShowAllTitle, ShowAllDesc,
|
||||
[]()
|
||||
[]
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
ScopedUndoBatch undoBatch(ShowAllEntitiesUndoRedoDesc);
|
||||
|
||||
EnumerateEditorEntities(
|
||||
[](AZ::EntityId entityId)
|
||||
[](const AZ::EntityId entityId)
|
||||
{
|
||||
ScopedUndoBatch::MarkEntityDirty(entityId);
|
||||
SetEntityVisibility(entityId, true);
|
||||
@@ -2263,7 +2259,7 @@ namespace AzToolsFramework
|
||||
// select all entities in the level/scene
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::CTRL + Qt::Key_A) }, SelectAll, SelectAllTitle, SelectAllDesc,
|
||||
[this]()
|
||||
[this]
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
@@ -2303,7 +2299,7 @@ namespace AzToolsFramework
|
||||
// invert current selection
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I) }, InvertSelect, InvertSelectionTitle, InvertSelectionDesc,
|
||||
[this]()
|
||||
[this]
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
@@ -2350,17 +2346,10 @@ namespace AzToolsFramework
|
||||
// duplicate selection
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::CTRL + Qt::Key_D) }, DuplicateSelect, DuplicateTitle, DuplicateDesc,
|
||||
[]()
|
||||
[]
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
// Clear Widget selection - Prevents issues caused by cloning entities while a property in the Reflected Property Editor
|
||||
// is being edited.
|
||||
if (QApplication::focusWidget())
|
||||
{
|
||||
QApplication::focusWidget()->clearFocus();
|
||||
}
|
||||
|
||||
ScopedUndoBatch undoBatch(DuplicateUndoRedoDesc);
|
||||
auto selectionCommand = AZStd::make_unique<SelectionCommand>(EntityIdList(), DuplicateUndoRedoDesc);
|
||||
selectionCommand->SetParent(undoBatch.GetUndoBatch());
|
||||
@@ -2375,7 +2364,7 @@ namespace AzToolsFramework
|
||||
// delete selection
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::Key_Delete) }, DeleteSelect, DeleteTitle, DeleteDesc,
|
||||
[this]()
|
||||
[this]
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
@@ -2392,21 +2381,21 @@ namespace AzToolsFramework
|
||||
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::Key_Space) }, EditEscaspe, "", "",
|
||||
[this]()
|
||||
[this]
|
||||
{
|
||||
DeselectEntities();
|
||||
});
|
||||
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::Key_P) }, EditPivot, TogglePivotTitleEditMenu, TogglePivotDesc,
|
||||
[this]()
|
||||
[this]
|
||||
{
|
||||
ToggleCenterPivotSelection();
|
||||
});
|
||||
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::Key_R) }, EditReset, ResetEntityTransformTitle, ResetEntityTransformDesc,
|
||||
[this]()
|
||||
[this]
|
||||
{
|
||||
switch (m_mode)
|
||||
{
|
||||
@@ -2424,50 +2413,14 @@ namespace AzToolsFramework
|
||||
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::CTRL + Qt::Key_R) }, EditResetManipulator, ResetManipulatorTitle, ResetManipulatorDesc,
|
||||
AZStd::bind(AZStd::mem_fn(&EditorTransformComponentSelection::DelegateClearManipulatorOverride), this));
|
||||
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::ALT + Qt::Key_R) }, EditResetLocal, ResetTransformLocalTitle, ResetTransformLocalDesc,
|
||||
[this]()
|
||||
[this]
|
||||
{
|
||||
switch (m_mode)
|
||||
{
|
||||
case Mode::Rotation:
|
||||
ResetOrientationForSelectedEntitiesLocal();
|
||||
break;
|
||||
case Mode::Scale:
|
||||
CopyScaleToSelectedEntitiesIndividualWorld(1.0f);
|
||||
break;
|
||||
case Mode::Translation:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::SHIFT + Qt::Key_R) }, EditResetWorld, ResetTransformWorldTitle, ResetTransformWorldDesc,
|
||||
[this]()
|
||||
{
|
||||
switch (m_mode)
|
||||
{
|
||||
case Mode::Rotation:
|
||||
{
|
||||
// begin an undo batch so operations inside CopyOrientation... and
|
||||
// DelegateClear... are grouped into a single undo/redo
|
||||
ScopedUndoBatch undoBatch{ ResetTransformWorldTitle };
|
||||
CopyOrientationToSelectedEntitiesIndividual(AZ::Quaternion::CreateIdentity());
|
||||
ClearManipulatorOrientationOverride();
|
||||
}
|
||||
break;
|
||||
case Mode::Scale:
|
||||
case Mode::Translation:
|
||||
break;
|
||||
}
|
||||
DelegateClearManipulatorOverride();
|
||||
});
|
||||
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::Key_U) }, ViewportUiVisible, "Toggle Viewport UI", "Hide/Show Viewport UI",
|
||||
[this]()
|
||||
[this]
|
||||
{
|
||||
SetAllViewportUiVisible(!m_viewportUiVisible);
|
||||
});
|
||||
@@ -3276,7 +3229,7 @@ namespace AzToolsFramework
|
||||
QAction* action = menu->addAction(QObject::tr(TogglePivotTitleRightClick));
|
||||
QObject::connect(
|
||||
action, &QAction::triggered, action,
|
||||
[this]()
|
||||
[this]
|
||||
{
|
||||
ToggleCenterPivotSelection();
|
||||
});
|
||||
@@ -3707,22 +3660,30 @@ namespace AzToolsFramework
|
||||
m_selectedEntityIdsAndManipulatorsDirty = true;
|
||||
}
|
||||
|
||||
void EditorTransformComponentSelection::EnteredComponentMode([[maybe_unused]] const AZStd::vector<AZ::Uuid>& componentModeTypes)
|
||||
void EditorTransformComponentSelection::OnEditorModeActivated(
|
||||
[[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode)
|
||||
{
|
||||
SetAllViewportUiVisible(false);
|
||||
if (mode == ViewportEditorMode::Component)
|
||||
{
|
||||
SetAllViewportUiVisible(false);
|
||||
|
||||
EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect();
|
||||
EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect();
|
||||
ToolsApplicationNotificationBus::Handler::BusDisconnect();
|
||||
EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect();
|
||||
EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect();
|
||||
ToolsApplicationNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorTransformComponentSelection::LeftComponentMode([[maybe_unused]] const AZStd::vector<AZ::Uuid>& componentModeTypes)
|
||||
void EditorTransformComponentSelection::OnEditorModeDeactivated(
|
||||
[[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode)
|
||||
{
|
||||
SetAllViewportUiVisible(true);
|
||||
if (mode == ViewportEditorMode::Component)
|
||||
{
|
||||
SetAllViewportUiVisible(true);
|
||||
|
||||
ToolsApplicationNotificationBus::Handler::BusConnect();
|
||||
EditorEntityVisibilityNotificationBus::Router::BusRouterConnect();
|
||||
EditorEntityLockComponentNotificationBus::Router::BusRouterConnect();
|
||||
ToolsApplicationNotificationBus::Handler::BusConnect();
|
||||
EditorEntityVisibilityNotificationBus::Router::BusRouterConnect();
|
||||
EditorEntityLockComponentNotificationBus::Router::BusRouterConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorTransformComponentSelection::CreateEntityManipulatorDeselectCommand(ScopedUndoBatch& undoBatch)
|
||||
|
||||
+5
-5
@@ -18,7 +18,7 @@
|
||||
#include <AzFramework/Viewport/CursorState.h>
|
||||
#include <AzToolsFramework/API/EditorCameraBus.h>
|
||||
#include <AzToolsFramework/Commands/EntityManipulatorCommand.h>
|
||||
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
|
||||
#include <AzToolsFramework/Editor/EditorContextMenuBus.h>
|
||||
#include <AzToolsFramework/Manipulators/BaseManipulator.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorLockComponentBus.h>
|
||||
@@ -153,7 +153,7 @@ namespace AzToolsFramework
|
||||
, private EditorTransformComponentSelectionRequestBus::Handler
|
||||
, private ToolsApplicationNotificationBus::Handler
|
||||
, private Camera::EditorCameraNotificationBus::Handler
|
||||
, private ComponentModeFramework::EditorComponentModeNotificationBus::Handler
|
||||
, private ViewportEditorModeNotificationsBus::Handler
|
||||
, private EditorEntityContextNotificationBus::Handler
|
||||
, private EditorEntityVisibilityNotificationBus::Router
|
||||
, private EditorEntityLockComponentNotificationBus::Router
|
||||
@@ -286,9 +286,9 @@ namespace AzToolsFramework
|
||||
// EditorContextLockComponentNotificationBus overrides ...
|
||||
void OnEntityLockChanged(bool locked) override;
|
||||
|
||||
// EditorComponentModeNotificationBus overrides ...
|
||||
void EnteredComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes) override;
|
||||
void LeftComponentMode(const AZStd::vector<AZ::Uuid>& componentModeTypes) override;
|
||||
// ViewportEditorModeNotificationsBus overrides ...
|
||||
void OnEditorModeActivated(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override;
|
||||
void OnEditorModeDeactivated(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override;
|
||||
|
||||
// EditorEntityContextNotificationBus overrides ...
|
||||
void OnStartPlayInEditor() override;
|
||||
|
||||
-2
@@ -31,8 +31,6 @@ namespace AzToolsFramework
|
||||
constexpr inline AZ::Crc32 EditPivot = AZ_CRC_CE("com.o3de.action.editortransform.editpivot");
|
||||
constexpr inline AZ::Crc32 EditReset = AZ_CRC_CE("com.o3de.action.editortransform.editreset");
|
||||
constexpr inline AZ::Crc32 EditResetManipulator = AZ_CRC_CE("com.o3de.action.editortransform.editresetmanipulator");
|
||||
constexpr inline AZ::Crc32 EditResetLocal = AZ_CRC_CE("com.o3de.action.editortransform.editresetlocal");
|
||||
constexpr inline AZ::Crc32 EditResetWorld = AZ_CRC_CE("com.o3de.action.editortransform.editresetworld");
|
||||
constexpr inline AZ::Crc32 ViewportUiVisible = AZ_CRC_CE("com.o3de.action.editortransform.viewportuivisible");
|
||||
//@}
|
||||
|
||||
|
||||
+18
-16
@@ -46,13 +46,14 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> ViewportEditorModeTracker::ActivateMode(
|
||||
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode)
|
||||
const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo, ViewportEditorMode mode)
|
||||
{
|
||||
auto& editorModes = m_viewportEditorModesMap[viewportEditorModeInfo.m_id];
|
||||
auto& editorModes = m_viewportEditorModesMap[ViewportEditorModeTrackerInfo.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));
|
||||
"Duplicate call to ActivateMode for mode '%u' on id '%s'", static_cast<AZ::u32>(mode),
|
||||
ViewportEditorModeTrackerInfo.m_id.ToString<AZStd::string>().c_str()));
|
||||
}
|
||||
|
||||
if (const auto result = editorModes.ActivateMode(mode);
|
||||
@@ -62,29 +63,30 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
ViewportEditorModeNotificationsBus::Event(
|
||||
viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeActivated, editorModes, mode);
|
||||
ViewportEditorModeTrackerInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeActivated, editorModes, mode);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> ViewportEditorModeTracker::DeactivateMode(
|
||||
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode)
|
||||
const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo, ViewportEditorMode mode)
|
||||
{
|
||||
ViewportEditorModes* editorModes = nullptr;
|
||||
bool modeWasActive = true;
|
||||
if (m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id))
|
||||
if (m_viewportEditorModesMap.count(ViewportEditorModeTrackerInfo.m_id))
|
||||
{
|
||||
editorModes = &m_viewportEditorModesMap.at(viewportEditorModeInfo.m_id);
|
||||
editorModes = &m_viewportEditorModesMap.at(ViewportEditorModeTrackerInfo.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));
|
||||
"Duplicate call to DeactivateMode for mode '%u' on id '%s'", static_cast<AZ::u32>(mode),
|
||||
ViewportEditorModeTrackerInfo.m_id.ToString<AZStd::string>().c_str()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
modeWasActive = false;
|
||||
editorModes = &m_viewportEditorModesMap[viewportEditorModeInfo.m_id];
|
||||
editorModes = &m_viewportEditorModesMap[ViewportEditorModeTrackerInfo.m_id];
|
||||
}
|
||||
|
||||
if(const auto result = editorModes->DeactivateMode(mode);
|
||||
@@ -94,7 +96,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
ViewportEditorModeNotificationsBus::Event(
|
||||
viewportEditorModeInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeDeactivated, *editorModes, mode);
|
||||
ViewportEditorModeTrackerInfo.m_id, &ViewportEditorModeNotificationsBus::Events::OnEditorModeDeactivated, *editorModes, mode);
|
||||
|
||||
if (modeWasActive)
|
||||
{
|
||||
@@ -103,14 +105,14 @@ namespace AzToolsFramework
|
||||
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));
|
||||
"Call to DeactivateMode for mode '%u' on id '%s' without precursor call to ActivateMode", static_cast<AZ::u32>(mode),
|
||||
ViewportEditorModeTrackerInfo.m_id.ToString<AZStd::string>().c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const
|
||||
const ViewportEditorModesInterface* ViewportEditorModeTracker::GetViewportEditorModes(const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo) const
|
||||
{
|
||||
if (auto editorModes = m_viewportEditorModesMap.find(viewportEditorModeInfo.m_id);
|
||||
if (auto editorModes = m_viewportEditorModesMap.find(ViewportEditorModeTrackerInfo.m_id);
|
||||
editorModes != m_viewportEditorModesMap.end())
|
||||
{
|
||||
return &editorModes->second;
|
||||
@@ -126,8 +128,8 @@ namespace AzToolsFramework
|
||||
return m_viewportEditorModesMap.size();
|
||||
}
|
||||
|
||||
bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const
|
||||
bool ViewportEditorModeTracker::IsViewportModeTracked(const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo) const
|
||||
{
|
||||
return m_viewportEditorModesMap.count(viewportEditorModeInfo.m_id) > 0;
|
||||
return m_viewportEditorModesMap.count(ViewportEditorModeTrackerInfo.m_id) > 0;
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+6
-6
@@ -42,14 +42,14 @@ namespace AzToolsFramework
|
||||
{
|
||||
public:
|
||||
// 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;
|
||||
AZ::Outcome<void, AZStd::string> ActivateMode(const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo, ViewportEditorMode mode) override;
|
||||
AZ::Outcome<void, AZStd::string> DeactivateMode(const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo, ViewportEditorMode mode) override;
|
||||
const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo) const override;
|
||||
size_t GetTrackedViewportCount() const override;
|
||||
bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const override;
|
||||
bool IsViewportModeTracked(const ViewportEditorModeTrackerInfo& ViewportEditorModeTrackerInfo) const override;
|
||||
|
||||
private:
|
||||
using ViewportEditorModesMap = AZStd::unordered_map<typename ViewportEditorModeInfo::IdType, ViewportEditorModes>;
|
||||
ViewportEditorModesMap m_viewportEditorModesMap; //!< Editor mode state per viewport.
|
||||
using ViewportEditorModesMap = AZStd::unordered_map<typename ViewportEditorModeTrackerInfo::IdType, ViewportEditorModes>;
|
||||
ViewportEditorModesMap m_viewportEditorModesMap; //!< Editor mode states per tracker.
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -339,7 +339,7 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
{
|
||||
// no background for the widget else each set of buttons/text-fields/etc would have a black box around them
|
||||
SetTransparentBackground(mainWindow);
|
||||
mainWindow->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
|
||||
mainWindow->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
|
||||
}
|
||||
|
||||
void ViewportUiDisplay::InitializeUiOverlay()
|
||||
|
||||
@@ -30,12 +30,14 @@ set(FILES
|
||||
API/AssetDatabaseBus.h
|
||||
API/ComponentEntityObjectBus.h
|
||||
API/ComponentEntitySelectionBus.h
|
||||
API/ComponentModeCollectionInterface.h
|
||||
API/EditorCameraBus.h
|
||||
API/EditorCameraBus.cpp
|
||||
API/EditorAnimationSystemRequestBus.h
|
||||
API/EditorEntityAPI.h
|
||||
API/EditorLevelNotificationBus.h
|
||||
API/ViewportEditorModeTrackerNotificationBus.h
|
||||
API/ViewportEditorModeTrackerNotificationBus.cpp
|
||||
API/EditorVegetationRequestsBus.h
|
||||
API/EditorPythonConsoleBus.h
|
||||
API/EditorPythonRunnerRequestsBus.h
|
||||
@@ -114,6 +116,10 @@ set(FILES
|
||||
Component/EditorLevelComponentAPIBus.h
|
||||
Component/EditorLevelComponentAPIComponent.cpp
|
||||
Component/EditorLevelComponentAPIComponent.h
|
||||
ContainerEntity/ContainerEntityInterface.h
|
||||
ContainerEntity/ContainerEntityNotificationBus.h
|
||||
ContainerEntity/ContainerEntitySystemComponent.cpp
|
||||
ContainerEntity/ContainerEntitySystemComponent.h
|
||||
Editor/EditorContextMenuBus.h
|
||||
Editor/EditorSettingsAPIBus.h
|
||||
Entity/EditorEntityStartStatus.h
|
||||
@@ -148,6 +154,8 @@ set(FILES
|
||||
Entity/SliceEditorEntityOwnershipService.h
|
||||
Entity/SliceEditorEntityOwnershipService.cpp
|
||||
Entity/SliceEditorEntityOwnershipServiceBus.h
|
||||
Entity/EntityUtilityComponent.h
|
||||
Entity/EntityUtilityComponent.cpp
|
||||
Fingerprinting/TypeFingerprinter.h
|
||||
Fingerprinting/TypeFingerprinter.cpp
|
||||
FocusMode/FocusModeInterface.h
|
||||
@@ -638,13 +646,22 @@ set(FILES
|
||||
Prefab/PrefabFocusHandler.cpp
|
||||
Prefab/PrefabFocusInterface.h
|
||||
Prefab/PrefabFocusNotificationBus.h
|
||||
Prefab/PrefabFocusPublicInterface.h
|
||||
Prefab/PrefabFocusUndo.h
|
||||
Prefab/PrefabFocusUndo.cpp
|
||||
Prefab/PrefabIdTypes.h
|
||||
Prefab/PrefabLoader.h
|
||||
Prefab/PrefabLoader.cpp
|
||||
Prefab/PrefabLoaderInterface.h
|
||||
Prefab/PrefabLoaderScriptingBus.h
|
||||
Prefab/ScriptingPrefabLoader.h
|
||||
Prefab/ScriptingPrefabLoader.cpp
|
||||
Prefab/PrefabSystemComponent.h
|
||||
Prefab/PrefabSystemComponent.cpp
|
||||
Prefab/PrefabSystemComponentInterface.h
|
||||
Prefab/PrefabSystemScriptingBus.h
|
||||
Prefab/PrefabSystemScriptingHandler.h
|
||||
Prefab/PrefabSystemScriptingHandler.cpp
|
||||
Prefab/Instance/Instance.h
|
||||
Prefab/Instance/Instance.cpp
|
||||
Prefab/Instance/InstanceSerializer.h
|
||||
@@ -667,6 +684,8 @@ set(FILES
|
||||
Prefab/Instance/TemplateInstanceMapperInterface.h
|
||||
Prefab/Link/Link.h
|
||||
Prefab/Link/Link.cpp
|
||||
Prefab/Procedural/ProceduralPrefabAsset.h
|
||||
Prefab/Procedural/ProceduralPrefabAsset.cpp
|
||||
Prefab/PrefabPublicHandler.h
|
||||
Prefab/PrefabPublicHandler.cpp
|
||||
Prefab/PrefabPublicInterface.h
|
||||
|
||||
@@ -131,13 +131,13 @@ namespace UnitTest
|
||||
m_app.reset(aznew ToolsTestApplication("ArchiveComponentTest"));
|
||||
m_app->Start(AzFramework::Application::Descriptor());
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
|
||||
if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr)
|
||||
{
|
||||
fileIoBase->SetAlias("@assets@", m_tempDir.GetDirectory());
|
||||
fileIoBase->SetAlias("@products@", m_tempDir.GetDirectory());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,10 +37,10 @@ namespace // anonymous
|
||||
|
||||
bool Search(const AzToolsFramework::AssetFileInfoList& assetList, const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
return AZStd::find_if(assetList.m_fileInfoList.begin(), assetList.m_fileInfoList.end(),
|
||||
[&](AzToolsFramework::AssetFileInfo fileInfo)
|
||||
{
|
||||
return fileInfo.m_assetId == assetId;
|
||||
return AZStd::find_if(assetList.m_fileInfoList.begin(), assetList.m_fileInfoList.end(),
|
||||
[&](AzToolsFramework::AssetFileInfo fileInfo)
|
||||
{
|
||||
return fileInfo.m_assetId == assetId;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -74,11 +74,11 @@ namespace UnitTest
|
||||
|
||||
m_application->Start(AzFramework::Application::Descriptor());
|
||||
|
||||
// By default @assets@ is setup to include the platform at the end. But this test is going to
|
||||
// By default @products@ is setup to include the platform at the end. But this test is going to
|
||||
// loop over platforms and it will be included as part of the relative path of the file.
|
||||
// So the asset folder for these tests have to point to the cache project root folder, which
|
||||
// doesn't include the platform.
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", cacheProjectRootFolder.c_str());
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", cacheProjectRootFolder.c_str());
|
||||
|
||||
for (int idx = 0; idx < s_totalAssets; idx++)
|
||||
{
|
||||
@@ -158,17 +158,17 @@ namespace UnitTest
|
||||
m_assetRegistry->RegisterAssetDependency(assets[5], AZ::Data::ProductDependency(assets[6], 0));
|
||||
m_assetRegistry->RegisterAssetDependency(assets[6], AZ::Data::ProductDependency(assets[7], 0));
|
||||
|
||||
// asset8 -> asset6
|
||||
// asset8 -> asset6
|
||||
m_assetRegistry->RegisterAssetDependency(assets[8], AZ::Data::ProductDependency(assets[6], 0));
|
||||
|
||||
// asset10 -> asset11
|
||||
// asset10 -> asset11
|
||||
m_assetRegistry->RegisterAssetDependency(assets[10], AZ::Data::ProductDependency(assets[11], 0));
|
||||
|
||||
// asset11 -> asset10
|
||||
// asset11 -> asset10
|
||||
m_assetRegistry->RegisterAssetDependency(assets[11], AZ::Data::ProductDependency(assets[10], 0));
|
||||
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
|
||||
@@ -203,10 +203,6 @@ namespace UnitTest
|
||||
|
||||
const AZStd::string engroot = AZ::Test::GetEngineRootPath();
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engroot.c_str());
|
||||
|
||||
AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath());
|
||||
assetRoot /= "Cache";
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@@ -219,7 +215,7 @@ namespace UnitTest
|
||||
delete m_application;
|
||||
}
|
||||
|
||||
AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override
|
||||
AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override
|
||||
{
|
||||
auto foundIter = m_assetRegistry->m_assetIdToInfo.find(id);
|
||||
if (foundIter != m_assetRegistry->m_assetIdToInfo.end())
|
||||
@@ -540,7 +536,7 @@ namespace UnitTest
|
||||
EXPECT_TRUE(Search(assetList, assets[7]));
|
||||
EXPECT_TRUE(Search(assetList, assets[8]));
|
||||
|
||||
// Removing the android flag from the asset should still produce the same result
|
||||
// Removing the android flag from the asset should still produce the same result
|
||||
m_assetSeedManager->RemoveSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
|
||||
assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC);
|
||||
@@ -564,7 +560,7 @@ namespace UnitTest
|
||||
EXPECT_TRUE(Search(assetList, assets[3]));
|
||||
EXPECT_TRUE(Search(assetList, assets[4]));
|
||||
|
||||
// Adding the android flag again to the asset
|
||||
// Adding the android flag again to the asset
|
||||
m_assetSeedManager->AddSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_ANDROID);
|
||||
assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::ANDROID_ID);
|
||||
|
||||
@@ -624,7 +620,7 @@ namespace UnitTest
|
||||
|
||||
EXPECT_EQ(assetList1.m_fileInfoList[0].m_assetId, assetList2.m_fileInfoList[0].m_assetId);
|
||||
EXPECT_GE(assetList2.m_fileInfoList[0].m_modificationTime, assetList1.m_fileInfoList[0].m_modificationTime); // file mod time should change
|
||||
|
||||
|
||||
// file hash should not change
|
||||
for (int idx = 0; idx < 5; idx++)
|
||||
{
|
||||
@@ -680,7 +676,7 @@ namespace UnitTest
|
||||
m_assetSeedManager->AddSeedAsset(assets[validFileIndex], AzFramework::PlatformFlags::Platform_PC, m_assetsPath[invalidFileIndex]);
|
||||
|
||||
const AzFramework::AssetSeedList& oldSeedList = m_assetSeedManager->GetAssetSeedList();
|
||||
|
||||
|
||||
for (const auto& seedInfo : oldSeedList)
|
||||
{
|
||||
if (seedInfo.m_assetId == assets[validFileIndex])
|
||||
|
||||
@@ -18,8 +18,6 @@ namespace UnitTests
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD1(GetAbsoluteAssetDatabaseLocation, bool(AZStd::string&));
|
||||
MOCK_METHOD0(GetAbsoluteDevGameFolderPath, const char* ());
|
||||
MOCK_METHOD0(GetAbsoluteDevRootFolderPath, const char* ());
|
||||
MOCK_METHOD2(GetRelativeProductPathFromFullSourceOrProductPath, bool(const AZStd::string& fullPath, AZStd::string& relativeProductPath));
|
||||
MOCK_METHOD3(GenerateRelativeSourcePath,
|
||||
bool(const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& watchFolder));
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/Entity/BehaviorEntity.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
#include <Entity/EntityUtilityComponent.h>
|
||||
#include <ToolsComponents/TransformComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
// Global variables for communicating between Lua test code and C++
|
||||
AZ::EntityId g_globalEntityId = AZ::EntityId{};
|
||||
AZStd::string g_globalString = "";
|
||||
AzFramework::BehaviorComponentId g_globalComponentId = {};
|
||||
AZStd::vector<AzToolsFramework::ComponentDetails> g_globalComponentDetails = {};
|
||||
bool g_globalBool = false;
|
||||
|
||||
class EntityUtilityComponentTests
|
||||
: public ToolsApplicationFixture
|
||||
{
|
||||
void InitProperties()
|
||||
{
|
||||
AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
|
||||
ASSERT_NE(componentApplicationRequests, nullptr);
|
||||
|
||||
auto behaviorContext = componentApplicationRequests->GetBehaviorContext();
|
||||
|
||||
ASSERT_NE(behaviorContext, nullptr);
|
||||
|
||||
behaviorContext->Property("g_globalEntityId", BehaviorValueProperty(&g_globalEntityId));
|
||||
behaviorContext->Property("g_globalString", BehaviorValueProperty(&g_globalString));
|
||||
behaviorContext->Property("g_globalComponentId", BehaviorValueProperty(&g_globalComponentId));
|
||||
behaviorContext->Property("g_globalBool", BehaviorValueProperty(&g_globalBool));
|
||||
behaviorContext->Property("g_globalComponentDetails", BehaviorValueProperty(&g_globalComponentDetails));
|
||||
|
||||
g_globalEntityId = AZ::EntityId{};
|
||||
g_globalString = AZStd::string{};
|
||||
g_globalComponentId = AzFramework::BehaviorComponentId{};
|
||||
g_globalBool = false;
|
||||
g_globalComponentDetails = AZStd::vector<AzToolsFramework::ComponentDetails>{};
|
||||
}
|
||||
|
||||
void SetUpEditorFixtureImpl() override
|
||||
{
|
||||
InitProperties();
|
||||
}
|
||||
|
||||
void TearDownEditorFixtureImpl() override
|
||||
{
|
||||
g_globalString.set_capacity(0); // Free all memory
|
||||
g_globalComponentDetails.set_capacity(0);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, CreateEntity)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalEntityId = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
my_entity = Entity(g_globalEntityId)
|
||||
g_globalString = my_entity:GetName()
|
||||
)LUA");
|
||||
|
||||
EXPECT_NE(g_globalEntityId, AZ::EntityId{});
|
||||
EXPECT_STREQ(g_globalString.c_str(), "test");
|
||||
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(g_globalEntityId);
|
||||
|
||||
ASSERT_NE(entity, nullptr);
|
||||
|
||||
// Test cleaning up, make sure the entity is destroyed
|
||||
AzToolsFramework::EntityUtilityBus::Broadcast(&AzToolsFramework::EntityUtilityBus::Events::ResetEntityContext);
|
||||
|
||||
entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(g_globalEntityId);
|
||||
|
||||
ASSERT_EQ(entity, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, CreateEntityEmptyName)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalEntityId = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("")
|
||||
)LUA");
|
||||
|
||||
EXPECT_NE(g_globalEntityId, AZ::EntityId{});
|
||||
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(g_globalEntityId);
|
||||
|
||||
ASSERT_NE(entity, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, FindComponent)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0 TransformComponent")
|
||||
)LUA");
|
||||
|
||||
EXPECT_TRUE(g_globalComponentId.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, InvalidComponentName)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
sc.Execute(R"LUA(
|
||||
ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "ThisIsNotAComponent-Error")
|
||||
)LUA");
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
EXPECT_FALSE(g_globalComponentId.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, InvalidComponentId)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
sc.Execute(R"LUA(
|
||||
ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "{1234-hello-world-this-is-not-an-id}")
|
||||
)LUA");
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // Should get 1 error stating the type id is not valid
|
||||
EXPECT_FALSE(g_globalComponentId.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, CreateComponent)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "ScriptEditorComponent")
|
||||
)LUA");
|
||||
|
||||
EXPECT_TRUE(g_globalComponentId.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, UpdateComponent)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalEntityId = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
comp_id = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(g_globalEntityId, "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent")
|
||||
json_update = [[
|
||||
{
|
||||
"Transform Data": { "Rotate": [0.0, 0.1, 180.0] }
|
||||
}
|
||||
]]
|
||||
g_globalBool = EntityUtilityBus.Broadcast.UpdateComponentForEntity(g_globalEntityId, comp_id, json_update);
|
||||
)LUA");
|
||||
|
||||
EXPECT_TRUE(g_globalBool);
|
||||
EXPECT_NE(g_globalEntityId, AZ::EntityId(AZ::EntityId::InvalidEntityId));
|
||||
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(g_globalEntityId);
|
||||
|
||||
auto* transformComponent = entity->FindComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
|
||||
ASSERT_NE(transformComponent, nullptr);
|
||||
|
||||
AZ::Vector3 localRotation = transformComponent->GetLocalRotationQuaternion().GetEulerDegrees();
|
||||
|
||||
EXPECT_EQ(localRotation, AZ::Vector3(.0f, 0.1f, 180.0f));
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, GetComponentJson)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalString = EntityUtilityBus.Broadcast.GetComponentDefaultJson("ScriptEditorComponent")
|
||||
)LUA");
|
||||
|
||||
EXPECT_STRNE(g_globalString.c_str(), "");
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, GetComponentJsonDoesNotExist)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
sc.Execute(R"LUA(
|
||||
g_globalString = EntityUtilityBus.Broadcast.GetComponentDefaultJson("404")
|
||||
)LUA");
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // 1 error: Failed to find component id for type name 404
|
||||
|
||||
EXPECT_STREQ(g_globalString.c_str(), "");
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, SearchComponents)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalComponentDetails = EntityUtilityBus.Broadcast.FindMatchingComponents("Transform*")
|
||||
)LUA");
|
||||
|
||||
// There should be 2 transform components
|
||||
EXPECT_EQ(g_globalComponentDetails.size(), 2);
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, SearchComponentsNotFound)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalComponentDetails = EntityUtilityBus.Broadcast.FindMatchingComponents("404")
|
||||
)LUA");
|
||||
|
||||
EXPECT_EQ(g_globalComponentDetails.size(), 0);
|
||||
}
|
||||
}
|
||||
@@ -181,8 +181,8 @@ namespace UnitTest
|
||||
|
||||
const char* dir = m_componentApplication->GetExecutableFolder();
|
||||
|
||||
m_localFileIO.SetAlias("@assets@", dir);
|
||||
m_localFileIO.SetAlias("@devassets@", dir);
|
||||
m_localFileIO.SetAlias("@products@", dir);
|
||||
m_localFileIO.SetAlias("@projectroot@", dir);
|
||||
}
|
||||
|
||||
void Destroy()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user