+6
-4
@@ -43,8 +43,7 @@ namespace AzToolsFramework
|
||||
};
|
||||
|
||||
//! Provides a bus to notify when the different editor modes are entered/exit.
|
||||
class ViewportEditorModeNotifications
|
||||
: public AZ::EBusTraits
|
||||
class ViewportEditorModeNotifications : public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -58,14 +57,17 @@ namespace AzToolsFramework
|
||||
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)
|
||||
virtual void OnEditorModeActivated(
|
||||
[[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode)
|
||||
{
|
||||
}
|
||||
|
||||
//! Notifies subscribers of the a given viewport to the deactivation of the specified editor mode.
|
||||
virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode)
|
||||
virtual void OnEditorModeDeactivated(
|
||||
[[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using ViewportEditorModeNotificationsBus = AZ::EBus<ViewportEditorModeNotifications>;
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ namespace AzToolsFramework
|
||||
private slots:
|
||||
void SourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||
private:
|
||||
int m_numberOfItemsDisplayed = 50;
|
||||
AZ::u64 m_numberOfItemsDisplayed = 0;
|
||||
int m_displayedItemsCounter = 0;
|
||||
QPointer<AssetBrowserFilterModel> m_filterModel;
|
||||
QMap<int, QModelIndex> m_indexMap;
|
||||
|
||||
+52
@@ -137,6 +137,7 @@ namespace AzToolsFramework
|
||||
if (componentTypeIt == m_activeComponentTypes.end())
|
||||
{
|
||||
m_activeComponentTypes.push_back(componentType);
|
||||
m_viewportUiHandlers.emplace_back(componentType);
|
||||
}
|
||||
|
||||
// see if we already have a ComponentModeBuilder for the specific component on this entity
|
||||
@@ -225,6 +226,7 @@ namespace AzToolsFramework
|
||||
if (!m_entitiesAndComponentModes.empty())
|
||||
{
|
||||
RefreshActions();
|
||||
PopulateViewportUi();
|
||||
}
|
||||
|
||||
// if entering ComponentMode not as an undo/redo step (an action was
|
||||
@@ -285,6 +287,10 @@ namespace AzToolsFramework
|
||||
componentModeCommand.release();
|
||||
}
|
||||
|
||||
// remove the component mode viewport border
|
||||
ViewportUi::ViewportUiRequestBus::Event(
|
||||
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RemoveViewportBorder);
|
||||
|
||||
// notify listeners the editor has left ComponentMode - listeners may
|
||||
// wish to modify state to indicate this (e.g. appearance, functionality etc.)
|
||||
m_viewportEditorModeTracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Component);
|
||||
@@ -301,6 +307,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
m_entitiesAndComponentModeBuilders.clear();
|
||||
m_activeComponentTypes.clear();
|
||||
m_viewportUiHandlers.clear();
|
||||
|
||||
m_componentMode = false;
|
||||
m_selectedComponentModeIndex = 0;
|
||||
@@ -385,6 +392,24 @@ namespace AzToolsFramework
|
||||
return m_activeComponentTypes.size() > 1;
|
||||
}
|
||||
|
||||
static ComponentModeViewportUi* FindViewportUiHandlerForType(
|
||||
AZStd::vector<ComponentModeViewportUi>& viewportUiHandlers, const AZ::Uuid& componentType)
|
||||
{
|
||||
auto handler = AZStd::find_if(
|
||||
viewportUiHandlers.begin(), viewportUiHandlers.end(),
|
||||
[componentType](const ComponentModeViewportUi& handler)
|
||||
{
|
||||
return handler.GetComponentType() == componentType;
|
||||
});
|
||||
|
||||
if (handler == viewportUiHandlers.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
bool ComponentModeCollection::ActiveComponentModeChanged(const AZ::Uuid& previousComponentType)
|
||||
{
|
||||
if (m_activeComponentTypes[m_selectedComponentModeIndex] != previousComponentType)
|
||||
@@ -410,6 +435,20 @@ namespace AzToolsFramework
|
||||
// replace the current component mode by invoking the builder
|
||||
// for the new 'active' component mode
|
||||
componentMode.m_componentMode = componentModeBuilder->m_componentModeBuilder();
|
||||
|
||||
// populate the viewport UI with the new component mode
|
||||
PopulateViewportUi();
|
||||
|
||||
// set the appropriate viewportUiHandler to active
|
||||
if (auto viewportUiHandler =
|
||||
FindViewportUiHandlerForType(m_viewportUiHandlers, m_activeComponentTypes[m_selectedComponentModeIndex]))
|
||||
{
|
||||
viewportUiHandler->SetComponentModeViewportUiActive(true);
|
||||
}
|
||||
|
||||
ViewportUi::ViewportUiRequestBus::Event(
|
||||
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder,
|
||||
componentMode.m_componentMode->GetComponentModeName().c_str());
|
||||
}
|
||||
|
||||
RefreshActions();
|
||||
@@ -519,5 +558,18 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentModeCollection::PopulateViewportUi()
|
||||
{
|
||||
// update viewport UI for new component type
|
||||
if (m_selectedComponentModeIndex < m_activeComponentTypes.size())
|
||||
{
|
||||
// iterate over all entities and their active Component Mode, populate viewport UI for the new mode
|
||||
for (auto& entityAndComponentMode : m_entitiesAndComponentModes)
|
||||
{
|
||||
// build viewport UI based on current state
|
||||
entityAndComponentMode.m_componentMode->PopulateViewportUi();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace ComponentModeFramework
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ namespace AzToolsFramework
|
||||
GetEntityComponentIdPair(), elementIdsToDisplay);
|
||||
// create the component mode border with the specific name for this component mode
|
||||
ViewportUi::ViewportUiRequestBus::Event(
|
||||
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateComponentModeBorder,
|
||||
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder,
|
||||
GetComponentModeName());
|
||||
// set the EntityComponentId for this ComponentMode to active in the ComponentModeViewportUi system
|
||||
ComponentModeViewportUiRequestBus::Event(
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace AzToolsFramework
|
||||
virtual SettingOutcome GetValue(const AZStd::string_view path) = 0;
|
||||
virtual SettingOutcome SetValue(const AZStd::string_view path, const AZStd::any& value) = 0;
|
||||
virtual ConsoleColorTheme GetConsoleColorTheme() const = 0;
|
||||
virtual int GetMaxNumberOfItemsShownInSearchView() const = 0;
|
||||
virtual AZ::u64 GetMaxNumberOfItemsShownInSearchView() const = 0;
|
||||
};
|
||||
|
||||
using EditorSettingsAPIBus = AZ::EBus<EditorSettingsAPIRequests>;
|
||||
|
||||
+4
-2
@@ -28,8 +28,10 @@ namespace AzToolsFramework
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Triggered when the editor focus is changed to a different entity.
|
||||
//! @param entityId The entity the focus has been moved to.
|
||||
virtual void OnEditorFocusChanged(AZ::EntityId entityId) = 0;
|
||||
//! @param previousFocusEntityId The entity the focus has been moved from.
|
||||
//! @param newFocusEntityId The entity the focus has been moved to.
|
||||
virtual void OnEditorFocusChanged(
|
||||
[[maybe_unused]] AZ::EntityId previousFocusEntityId, [[maybe_unused]] AZ::EntityId newFocusEntityId) {}
|
||||
|
||||
protected:
|
||||
~FocusModeNotifications() = default;
|
||||
|
||||
+2
-1
@@ -83,8 +83,9 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
AZ::EntityId previousFocusEntityId = m_focusRoot;
|
||||
m_focusRoot = entityId;
|
||||
FocusModeNotificationBus::Broadcast(&FocusModeNotifications::OnEditorFocusChanged, m_focusRoot);
|
||||
FocusModeNotificationBus::Broadcast(&FocusModeNotifications::OnEditorFocusChanged, previousFocusEntityId, m_focusRoot);
|
||||
}
|
||||
|
||||
void FocusModeSystemComponent::ClearFocusRoot([[maybe_unused]] AzFramework::EntityContextId entityContextId)
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
return AZ::Intersect::IntersectRayBox(
|
||||
rayOrigin, rayDirection, m_center, m_axis1, m_axis2, m_axis3, m_halfExtents.GetX(), m_halfExtents.GetY(),
|
||||
m_halfExtents.GetZ(), rayIntersectionDistance) > 0;
|
||||
m_halfExtents.GetZ(), rayIntersectionDistance);
|
||||
}
|
||||
|
||||
void ManipulatorBoundBox::SetShapeData(const BoundRequestShapeBase& shapeData)
|
||||
|
||||
@@ -262,7 +262,7 @@ namespace AzToolsFramework
|
||||
|
||||
if (assetId.IsValid())
|
||||
{
|
||||
asset.Create(assetId, true);
|
||||
asset.Create(assetId, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,12 +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
|
||||
{
|
||||
@@ -28,10 +30,12 @@ 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();
|
||||
}
|
||||
@@ -61,6 +65,44 @@ namespace AzToolsFramework::Prefab
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -85,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())
|
||||
@@ -122,17 +152,10 @@ 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
|
||||
@@ -161,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())
|
||||
@@ -200,7 +234,7 @@ namespace AzToolsFramework::Prefab
|
||||
m_instanceFocusVector.clear();
|
||||
|
||||
// Focus on the root prefab (AZ::EntityId() will default to it)
|
||||
FocusOnOwningPrefab(AZ::EntityId());
|
||||
FocusOnPrefabInstanceOwningEntityId(AZ::EntityId());
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::RefreshInstanceFocusList()
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#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
|
||||
@@ -28,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:
|
||||
@@ -39,10 +41,14 @@ namespace AzToolsFramework::Prefab
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
@@ -43,6 +43,12 @@ namespace AzToolsFramework
|
||||
m_instanceToTemplateInterface = AZ::Interface<InstanceToTemplateInterface>::Get();
|
||||
AZ_Assert(m_instanceToTemplateInterface, "PrefabPublicHandler - Could not retrieve instance of InstanceToTemplateInterface");
|
||||
|
||||
m_prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
|
||||
AZ_Assert(m_prefabFocusInterface, "Could not get PrefabFocusInterface on PrefabPublicHandler construction.");
|
||||
|
||||
m_prefabFocusPublicInterface = AZ::Interface<PrefabFocusPublicInterface>::Get();
|
||||
AZ_Assert(m_prefabFocusPublicInterface, "Could not get PrefabFocusPublicInterface on PrefabPublicHandler construction.");
|
||||
|
||||
m_prefabLoaderInterface = AZ::Interface<PrefabLoaderInterface>::Get();
|
||||
AZ_Assert(m_prefabLoaderInterface, "Could not get PrefabLoaderInterface on PrefabPublicHandler construction.");
|
||||
|
||||
@@ -552,6 +558,13 @@ namespace AzToolsFramework
|
||||
|
||||
PrefabEntityResult PrefabPublicHandler::CreateEntity(AZ::EntityId parentId, const AZ::Vector3& position)
|
||||
{
|
||||
// If the parent is invalid, parent to the container of the currently focused prefab.
|
||||
if (!parentId.IsValid())
|
||||
{
|
||||
AzFramework::EntityContextId editorEntityContextId = AzToolsFramework::GetEntityContextId();
|
||||
parentId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId);
|
||||
}
|
||||
|
||||
InstanceOptionalReference owningInstanceOfParentEntity = GetOwnerInstanceByEntityId(parentId);
|
||||
if (!owningInstanceOfParentEntity)
|
||||
{
|
||||
@@ -968,13 +981,13 @@ namespace AzToolsFramework
|
||||
return AZ::Failure(AZStd::string("No entities to duplicate."));
|
||||
}
|
||||
|
||||
const EntityIdList entityIdsNoLevelInstance = GenerateEntityIdListWithoutLevelInstance(entityIds);
|
||||
if (entityIdsNoLevelInstance.empty())
|
||||
const EntityIdList entityIdsNoFocusContainer = GenerateEntityIdListWithoutFocusedInstanceContainer(entityIds);
|
||||
if (entityIdsNoFocusContainer.empty())
|
||||
{
|
||||
return AZ::Failure(AZStd::string("No entities to duplicate because only instance selected is the level instance."));
|
||||
return AZ::Failure(AZStd::string("No entities to duplicate because only instance selected is the container entity of the focused instance."));
|
||||
}
|
||||
|
||||
if (!EntitiesBelongToSameInstance(entityIdsNoLevelInstance))
|
||||
if (!EntitiesBelongToSameInstance(entityIdsNoFocusContainer))
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Cannot duplicate multiple entities belonging to different instances with one operation."
|
||||
"Change your selection to contain entities in the same instance."));
|
||||
@@ -982,7 +995,7 @@ namespace AzToolsFramework
|
||||
|
||||
// We've already verified the entities are all owned by the same instance,
|
||||
// so we can just retrieve our instance from the first entity in the list.
|
||||
AZ::EntityId firstEntityIdToDuplicate = entityIdsNoLevelInstance[0];
|
||||
AZ::EntityId firstEntityIdToDuplicate = entityIdsNoFocusContainer[0];
|
||||
InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDuplicate);
|
||||
if (!commonOwningInstance.has_value())
|
||||
{
|
||||
@@ -1002,7 +1015,7 @@ namespace AzToolsFramework
|
||||
|
||||
// This will cull out any entities that have ancestors in the list, since we will end up duplicating
|
||||
// the full nested hierarchy with what is returned from RetrieveAndSortPrefabEntitiesAndInstances
|
||||
AzToolsFramework::EntityIdSet duplicationSet = AzToolsFramework::GetCulledEntityHierarchy(entityIdsNoLevelInstance);
|
||||
AzToolsFramework::EntityIdSet duplicationSet = AzToolsFramework::GetCulledEntityHierarchy(entityIdsNoFocusContainer);
|
||||
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
@@ -1039,10 +1052,10 @@ namespace AzToolsFramework
|
||||
DuplicateNestedEntitiesInInstance(commonOwningInstance->get(),
|
||||
entities, instanceDomAfter, duplicatedEntityAndInstanceIds, duplicateEntityAliasMap);
|
||||
|
||||
PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication");
|
||||
PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication", false);
|
||||
command->SetParent(undoBatch.GetUndoBatch());
|
||||
command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId());
|
||||
command->RedoBatched();
|
||||
command->Redo();
|
||||
|
||||
DuplicateNestedInstancesInInstance(commonOwningInstance->get(),
|
||||
instances, instanceDomAfter, duplicatedEntityAndInstanceIds, newInstanceAliasToOldInstanceMap);
|
||||
@@ -1106,19 +1119,21 @@ namespace AzToolsFramework
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants)
|
||||
{
|
||||
const EntityIdList entityIdsNoLevelInstance = GenerateEntityIdListWithoutLevelInstance(entityIds);
|
||||
// Remove the container entity of the focused prefab from the list, if it is included.
|
||||
const EntityIdList entityIdsNoFocusContainer = GenerateEntityIdListWithoutFocusedInstanceContainer(entityIds);
|
||||
|
||||
if (entityIdsNoLevelInstance.empty())
|
||||
if (entityIdsNoFocusContainer.empty())
|
||||
{
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
if (!EntitiesBelongToSameInstance(entityIdsNoLevelInstance))
|
||||
// All entities in this list need to belong to the same prefab instance for the operation to be valid.
|
||||
if (!EntitiesBelongToSameInstance(entityIdsNoFocusContainer))
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Cannot delete multiple entities belonging to different instances with one operation."));
|
||||
}
|
||||
|
||||
AZ::EntityId firstEntityIdToDelete = entityIdsNoLevelInstance[0];
|
||||
AZ::EntityId firstEntityIdToDelete = entityIdsNoFocusContainer[0];
|
||||
InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDelete);
|
||||
|
||||
// If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you
|
||||
@@ -1128,8 +1143,15 @@ namespace AzToolsFramework
|
||||
commonOwningInstance = commonOwningInstance->get().GetParentInstance();
|
||||
}
|
||||
|
||||
// We only allow explicit deletions for entities inside the currently focused prefab.
|
||||
AzFramework::EntityContextId editorEntityContextId = AzToolsFramework::GetEntityContextId();
|
||||
if (&m_prefabFocusInterface->GetFocusedPrefabInstance(editorEntityContextId)->get() != &commonOwningInstance->get())
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Cannot delete entities belonging to an instance that is not being edited."));
|
||||
}
|
||||
|
||||
// Retrieve entityList from entityIds
|
||||
EntityList inputEntityList = EntityIdListToEntityList(entityIdsNoLevelInstance);
|
||||
EntityList inputEntityList = EntityIdListToEntityList(entityIdsNoFocusContainer);
|
||||
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
@@ -1186,7 +1208,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
else
|
||||
{
|
||||
for (AZ::EntityId entityId : entityIdsNoLevelInstance)
|
||||
for (AZ::EntityId entityId : entityIdsNoFocusContainer)
|
||||
{
|
||||
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
|
||||
// If this is the container entity, it actually represents the instance so get its owner
|
||||
@@ -1227,9 +1249,12 @@ namespace AzToolsFramework
|
||||
return AZ::Failure(AZStd::string("Cannot detach Prefab Instance with invalid container entity."));
|
||||
}
|
||||
|
||||
if (IsLevelInstanceContainerEntity(containerEntityId))
|
||||
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
if (containerEntityId == m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId))
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Cannot detach level Prefab Instance."));
|
||||
return AZ::Failure(AZStd::string("Cannot detach focused Prefab Instance."));
|
||||
}
|
||||
|
||||
InstanceOptionalReference owningInstance = GetOwnerInstanceByEntityId(containerEntityId);
|
||||
@@ -1298,7 +1323,7 @@ namespace AzToolsFramework
|
||||
Prefab::PrefabDom instanceDomAfter;
|
||||
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfter, parentInstance);
|
||||
|
||||
PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance detachment");
|
||||
PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance detachment", false);
|
||||
command->Capture(instanceDomBefore, instanceDomAfter, parentTemplateId);
|
||||
command->SetParent(undoBatch.GetUndoBatch());
|
||||
{
|
||||
@@ -1452,9 +1477,14 @@ namespace AzToolsFramework
|
||||
|
||||
AZStd::queue<AZ::Entity*> entityQueue;
|
||||
|
||||
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
AZ::EntityId focusedPrefabContainerEntityId =
|
||||
m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId);
|
||||
for (auto inputEntity : inputEntities)
|
||||
{
|
||||
if (inputEntity && !IsLevelInstanceContainerEntity(inputEntity->GetId()))
|
||||
if (inputEntity && inputEntity->GetId() != focusedPrefabContainerEntityId)
|
||||
{
|
||||
entityQueue.push(inputEntity);
|
||||
}
|
||||
@@ -1548,19 +1578,19 @@ namespace AzToolsFramework
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
EntityIdList PrefabPublicHandler::GenerateEntityIdListWithoutLevelInstance(
|
||||
EntityIdList PrefabPublicHandler::GenerateEntityIdListWithoutFocusedInstanceContainer(
|
||||
const EntityIdList& entityIds) const
|
||||
{
|
||||
EntityIdList outEntityIds;
|
||||
outEntityIds.reserve(entityIds.size()); // Actual size could be smaller.
|
||||
EntityIdList outEntityIds(entityIds);
|
||||
|
||||
for (const AZ::EntityId& entityId : entityIds)
|
||||
AzFramework::EntityContextId editorEntityContextId = AzToolsFramework::GetEntityContextId();
|
||||
AZ::EntityId focusedInstanceContainerEntityId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId);
|
||||
|
||||
if (auto iter = AZStd::find(outEntityIds.begin(), outEntityIds.end(), focusedInstanceContainerEntityId); iter != outEntityIds.end())
|
||||
{
|
||||
if (!IsLevelInstanceContainerEntity(entityId))
|
||||
{
|
||||
outEntityIds.emplace_back(entityId);
|
||||
}
|
||||
outEntityIds.erase(iter);
|
||||
}
|
||||
|
||||
return outEntityIds;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace AzToolsFramework
|
||||
Instance& commonRootEntityOwningInstance,
|
||||
EntityList& outEntities,
|
||||
AZStd::vector<Instance*>& outInstances) const;
|
||||
EntityIdList GenerateEntityIdListWithoutLevelInstance(const EntityIdList& entityIds) const;
|
||||
EntityIdList GenerateEntityIdListWithoutFocusedInstanceContainer(const EntityIdList& entityIds) const;
|
||||
|
||||
InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const;
|
||||
bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const;
|
||||
@@ -187,6 +187,8 @@ namespace AzToolsFramework
|
||||
|
||||
InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr;
|
||||
InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr;
|
||||
PrefabFocusInterface* m_prefabFocusInterface = nullptr;
|
||||
PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr;
|
||||
PrefabLoaderInterface* m_prefabLoaderInterface = nullptr;
|
||||
PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr;
|
||||
|
||||
|
||||
+26
-2
@@ -6,11 +6,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <API/ToolsApplicationAPI.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <Prefab/PrefabSystemScriptingHandler.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <Prefab/EditorPrefabComponent.h>
|
||||
#include <ToolsComponents/TransformComponent.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
@@ -61,9 +64,30 @@ namespace AzToolsFramework::Prefab
|
||||
entities.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
auto prefab = m_prefabSystemComponentInterface->CreatePrefab(entities, {}, AZ::IO::PathView(AZStd::string_view(filePath)));
|
||||
|
||||
bool result = false;
|
||||
[[maybe_unused]] AZ::EntityId commonRoot;
|
||||
EntityList topLevelEntities;
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(result, &AzToolsFramework::ToolsApplicationRequestBus::Events::FindCommonRootInactive,
|
||||
entities, commonRoot, &topLevelEntities);
|
||||
|
||||
auto containerEntity = AZStd::make_unique<AZ::Entity>();
|
||||
containerEntity->CreateComponent<Prefab::EditorPrefabComponent>();
|
||||
|
||||
for (AZ::Entity* entity : topLevelEntities)
|
||||
{
|
||||
AzToolsFramework::Components::TransformComponent* transformComponent =
|
||||
entity->FindComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
|
||||
if (transformComponent)
|
||||
{
|
||||
transformComponent->SetParent(containerEntity->GetId());
|
||||
}
|
||||
}
|
||||
|
||||
auto prefab = m_prefabSystemComponentInterface->CreatePrefab(
|
||||
entities, {}, AZ::IO::PathView(AZStd::string_view(filePath)), AZStd::move(containerEntity));
|
||||
|
||||
if (!prefab)
|
||||
{
|
||||
AZ_Error("PrefabSystemComponenent", false, "Failed to create prefab %s", filePath.c_str());
|
||||
|
||||
@@ -17,17 +17,16 @@ namespace AzToolsFramework
|
||||
{
|
||||
PrefabUndoBase::PrefabUndoBase(const AZStd::string& undoOperationName)
|
||||
: UndoSystem::URSequencePoint(undoOperationName)
|
||||
, m_changed(true)
|
||||
, m_templateId(InvalidTemplateId)
|
||||
{
|
||||
m_instanceToTemplateInterface = AZ::Interface<InstanceToTemplateInterface>::Get();
|
||||
AZ_Assert(m_instanceToTemplateInterface, "Failed to grab instance to template interface");
|
||||
}
|
||||
|
||||
//PrefabInstanceUndo
|
||||
PrefabUndoInstance::PrefabUndoInstance(const AZStd::string& undoOperationName)
|
||||
PrefabUndoInstance::PrefabUndoInstance(const AZStd::string& undoOperationName, const bool useImmediatePropagation)
|
||||
: PrefabUndoBase(undoOperationName)
|
||||
{
|
||||
m_useImmediatePropagation = useImmediatePropagation;
|
||||
}
|
||||
|
||||
void PrefabUndoInstance::Capture(
|
||||
@@ -43,17 +42,12 @@ namespace AzToolsFramework
|
||||
|
||||
void PrefabUndoInstance::Undo()
|
||||
{
|
||||
m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId, true);
|
||||
m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId, m_useImmediatePropagation);
|
||||
}
|
||||
|
||||
void PrefabUndoInstance::Redo()
|
||||
{
|
||||
m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, true);
|
||||
}
|
||||
|
||||
void PrefabUndoInstance::RedoBatched()
|
||||
{
|
||||
m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId);
|
||||
m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, m_useImmediatePropagation);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,14 +29,15 @@ namespace AzToolsFramework
|
||||
bool Changed() const override { return m_changed; }
|
||||
|
||||
protected:
|
||||
TemplateId m_templateId;
|
||||
TemplateId m_templateId = InvalidTemplateId;
|
||||
|
||||
PrefabDom m_redoPatch;
|
||||
PrefabDom m_undoPatch;
|
||||
|
||||
InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr;
|
||||
|
||||
bool m_changed;
|
||||
bool m_changed = true;
|
||||
bool m_useImmediatePropagation = true;
|
||||
};
|
||||
|
||||
//! handles the addition and removal of entities from instances
|
||||
@@ -44,7 +45,7 @@ namespace AzToolsFramework
|
||||
: public PrefabUndoBase
|
||||
{
|
||||
public:
|
||||
explicit PrefabUndoInstance(const AZStd::string& undoOperationName);
|
||||
explicit PrefabUndoInstance(const AZStd::string& undoOperationName, const bool useImmediatePropagation = true);
|
||||
|
||||
void Capture(
|
||||
const PrefabDom& initialState,
|
||||
@@ -53,7 +54,6 @@ namespace AzToolsFramework
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
void RedoBatched();
|
||||
};
|
||||
|
||||
//! handles entity updates, such as when the values on an entity change
|
||||
|
||||
@@ -23,10 +23,10 @@ namespace AzToolsFramework
|
||||
PrefabDom instanceDomAfterUpdate;
|
||||
PrefabDomUtils::StoreInstanceInPrefabDom(instance, instanceDomAfterUpdate);
|
||||
|
||||
PrefabUndoInstance* state = aznew Prefab::PrefabUndoInstance(undoMessage);
|
||||
PrefabUndoInstance* state = aznew Prefab::PrefabUndoInstance(undoMessage, false);
|
||||
state->Capture(instanceDomBeforeUpdate, instanceDomAfterUpdate, instance.GetTemplateId());
|
||||
state->SetParent(undoBatch);
|
||||
state->RedoBatched();
|
||||
state->Redo();
|
||||
}
|
||||
|
||||
LinkId CreateLink(
|
||||
|
||||
+2
-1
@@ -313,7 +313,8 @@ namespace AzToolsFramework
|
||||
StyledTreeView::StartCustomDrag(indexListSorted, supportedActions);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::OnEditorFocusChanged([[maybe_unused]] AZ::EntityId entityId)
|
||||
void EntityOutlinerTreeView::OnEditorFocusChanged(
|
||||
[[maybe_unused]] AZ::EntityId previousFocusEntityId, [[maybe_unused]] AZ::EntityId newFocusEntityId)
|
||||
{
|
||||
viewport()->repaint();
|
||||
}
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ namespace AzToolsFramework
|
||||
void leaveEvent(QEvent* event) override;
|
||||
|
||||
// FocusModeNotificationBus overrides ...
|
||||
void OnEditorFocusChanged(AZ::EntityId entityId) override;
|
||||
void OnEditorFocusChanged(AZ::EntityId previousFocusEntityId, AZ::EntityId newFocusEntityId) override;
|
||||
|
||||
//! Renders the left side of the item: appropriate background, branch lines, icons.
|
||||
void drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const override;
|
||||
|
||||
+9
-1
@@ -324,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;
|
||||
}
|
||||
@@ -552,6 +553,13 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not display the context menu if the item under the mouse cursor is not selectable.
|
||||
if (const QModelIndex& index = m_gui->m_objectTree->indexAt(pos); index.isValid()
|
||||
&& (index.flags() & Qt::ItemIsSelectable) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QMenu* contextMenu = new QMenu(this);
|
||||
|
||||
// Populate global context menu.
|
||||
|
||||
+45
-38
@@ -24,11 +24,12 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.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/Prefab/Instance/InstanceEntityMapperInterface.h>
|
||||
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorLayerComponentBus.h>
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiInterface.h>
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h>
|
||||
@@ -39,7 +40,6 @@
|
||||
#include <AzQtComponents/Components/StyleManager.h>
|
||||
#include <AzQtComponents/Components/Widgets/CardHeader.h>
|
||||
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QDialog>
|
||||
@@ -56,14 +56,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;
|
||||
@@ -129,10 +128,10 @@ 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;
|
||||
}
|
||||
|
||||
@@ -177,12 +176,16 @@ namespace AzToolsFramework
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
||||
|
||||
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
// Create Prefab
|
||||
{
|
||||
if (!selectedEntities.empty())
|
||||
{
|
||||
// Hide if the only selected entity is the Level Container
|
||||
if (selectedEntities.size() > 1 || !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0]))
|
||||
// Hide if the only selected entity is the Focused Instance Container
|
||||
if (selectedEntities.size() > 1 ||
|
||||
selectedEntities[0] != s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId))
|
||||
{
|
||||
bool layerInSelection = false;
|
||||
|
||||
@@ -247,21 +250,16 @@ namespace AzToolsFramework
|
||||
if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity))
|
||||
{
|
||||
// Edit Prefab
|
||||
if (prefabWipFeaturesEnabled)
|
||||
if (prefabWipFeaturesEnabled && !s_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(selectedEntity))
|
||||
{
|
||||
bool beingEdited = s_prefabFocusInterface->IsOwningPrefabBeingFocused(selectedEntity);
|
||||
QAction* editAction = menu->addAction(QObject::tr("Edit Prefab"));
|
||||
editAction->setToolTip(QObject::tr("Edit the prefab in focus mode."));
|
||||
|
||||
if (!beingEdited)
|
||||
{
|
||||
QAction* editAction = menu->addAction(QObject::tr("Edit Prefab"));
|
||||
editAction->setToolTip(QObject::tr("Edit the prefab in focus mode."));
|
||||
QObject::connect(editAction, &QAction::triggered, editAction, [selectedEntity] {
|
||||
ContextMenu_EditPrefab(selectedEntity);
|
||||
});
|
||||
|
||||
QObject::connect(editAction, &QAction::triggered, editAction, [selectedEntity] {
|
||||
ContextMenu_EditPrefab(selectedEntity);
|
||||
});
|
||||
|
||||
itemWasShown = true;
|
||||
}
|
||||
itemWasShown = true;
|
||||
}
|
||||
|
||||
// Save Prefab
|
||||
@@ -290,8 +288,9 @@ namespace AzToolsFramework
|
||||
|
||||
QAction* deleteAction = menu->addAction(QObject::tr("Delete"));
|
||||
QObject::connect(deleteAction, &QAction::triggered, deleteAction, [] { ContextMenu_DeleteSelected(); });
|
||||
if (selectedEntities.size() == 0 ||
|
||||
(selectedEntities.size() == 1 && s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0])))
|
||||
|
||||
if (selectedEntities.empty() ||
|
||||
(selectedEntities.size() == 1 && selectedEntities[0] == s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId)))
|
||||
{
|
||||
deleteAction->setDisabled(true);
|
||||
}
|
||||
@@ -299,17 +298,17 @@ namespace AzToolsFramework
|
||||
// Detach Prefab
|
||||
if (selectedEntities.size() == 1)
|
||||
{
|
||||
AZ::EntityId selectedEntity = selectedEntities[0];
|
||||
AZ::EntityId selectedEntityId = selectedEntities[0];
|
||||
|
||||
if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity) &&
|
||||
!s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntity))
|
||||
if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntityId) &&
|
||||
selectedEntityId != s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId))
|
||||
{
|
||||
QAction* detachPrefabAction = menu->addAction(QObject::tr("Detach Prefab..."));
|
||||
QObject::connect(
|
||||
detachPrefabAction, &QAction::triggered, detachPrefabAction,
|
||||
[selectedEntity]
|
||||
[selectedEntityId]
|
||||
{
|
||||
ContextMenu_DetachPrefab(selectedEntity);
|
||||
ContextMenu_DetachPrefab(selectedEntityId);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -317,7 +316,7 @@ namespace AzToolsFramework
|
||||
|
||||
void PrefabIntegrationManager::OnEscape()
|
||||
{
|
||||
s_prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId());
|
||||
s_prefabFocusPublicInterface->FocusOnOwningPrefab(AZ::EntityId());
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const
|
||||
@@ -338,13 +337,21 @@ namespace AzToolsFramework
|
||||
QWidget* activeWindow = QApplication::activeWindow();
|
||||
const AZStd::string prefabFilesPath = "@projectroot@/Prefabs";
|
||||
|
||||
// Remove Level entity if it's part of the list
|
||||
|
||||
auto levelContainerIter =
|
||||
AZStd::find(selectedEntities.begin(), selectedEntities.end(), s_prefabPublicInterface->GetLevelInstanceContainerEntityId());
|
||||
if (levelContainerIter != selectedEntities.end())
|
||||
// Remove focused instance container entity if it's part of the list
|
||||
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
auto focusedContainerIter = AZStd::find(
|
||||
selectedEntities.begin(), selectedEntities.end(),
|
||||
s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId));
|
||||
if (focusedContainerIter != selectedEntities.end())
|
||||
{
|
||||
selectedEntities.erase(levelContainerIter);
|
||||
selectedEntities.erase(focusedContainerIter);
|
||||
}
|
||||
|
||||
if (selectedEntities.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Set default folder for prefabs
|
||||
@@ -490,7 +497,7 @@ namespace AzToolsFramework
|
||||
|
||||
void PrefabIntegrationManager::ContextMenu_EditPrefab(AZ::EntityId containerEntity)
|
||||
{
|
||||
s_prefabFocusInterface->FocusOnOwningPrefab(containerEntity);
|
||||
s_prefabFocusPublicInterface->FocusOnOwningPrefab(containerEntity);
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::ContextMenu_SavePrefab(AZ::EntityId containerEntity)
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ namespace AzToolsFramework
|
||||
|
||||
namespace Prefab
|
||||
{
|
||||
class PrefabFocusInterface;
|
||||
class PrefabFocusPublicInterface;
|
||||
class PrefabLoaderInterface;
|
||||
|
||||
//! Structure for saving/retrieving user settings related to prefab workflows.
|
||||
@@ -144,7 +144,7 @@ namespace AzToolsFramework
|
||||
|
||||
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;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx>
|
||||
|
||||
@@ -35,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;
|
||||
}
|
||||
}
|
||||
@@ -83,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);
|
||||
}
|
||||
@@ -105,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;
|
||||
}
|
||||
@@ -178,12 +178,6 @@ namespace AzToolsFramework
|
||||
|
||||
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
|
||||
// We hide the root instance container entity from the Outliner, so avoid drawing its full container on children
|
||||
if (m_prefabPublicInterface->IsLevelInstanceContainerEntity(entityId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const QTreeView* outlinerTreeView(qobject_cast<const QTreeView*>(option.widget));
|
||||
const int ancestorLeft = outlinerTreeView->visualRect(index).left() + (m_prefabBorderThickness / 2) - 1;
|
||||
const int curveRectSize = m_prefabCapsuleRadius * 2;
|
||||
@@ -191,7 +185,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;
|
||||
}
|
||||
@@ -329,7 +323,7 @@ namespace AzToolsFramework
|
||||
if (prefabWipFeaturesEnabled)
|
||||
{
|
||||
// Focus on this prefab
|
||||
m_prefabFocusInterface->FocusOnOwningPrefab(entityId);
|
||||
m_prefabFocusPublicInterface->FocusOnOwningPrefab(entityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace AzToolsFramework
|
||||
|
||||
namespace Prefab
|
||||
{
|
||||
class PrefabFocusInterface;
|
||||
class PrefabFocusPublicInterface;
|
||||
class PrefabPublicInterface;
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace AzToolsFramework
|
||||
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
|
||||
|
||||
+26
-7
@@ -9,6 +9,7 @@
|
||||
#include "EditorHelpers.h"
|
||||
|
||||
#include <AzCore/Console/Console.h>
|
||||
#include <AzCore/Math/VectorConversions.h>
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AzFramework/Viewport/ViewportScreen.h>
|
||||
@@ -150,6 +151,11 @@ namespace AzToolsFramework
|
||||
"EditorHelpers - "
|
||||
"Focus Mode Interface could not be found. "
|
||||
"Check that it is being correctly initialized.");
|
||||
|
||||
AZStd::vector<AZStd::unique_ptr<InvalidClick>> invalidClicks;
|
||||
invalidClicks.push_back(AZStd::make_unique<FadingText>("Not in focus"));
|
||||
invalidClicks.push_back(AZStd::make_unique<ExpandingFadingCircles>());
|
||||
m_invalidClicks = AZStd::make_unique<InvalidClicks>(AZStd::move(invalidClicks));
|
||||
}
|
||||
|
||||
CursorEntityIdQuery EditorHelpers::FindEntityIdUnderCursor(
|
||||
@@ -213,13 +219,20 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
// Verify if the entity Id corresponds to an entity that is focused; if not, halt selection.
|
||||
if (!IsSelectableAccordingToFocusMode(entityIdUnderCursor))
|
||||
// verify if the entity Id corresponds to an entity that is focused; if not, halt selection.
|
||||
if (entityIdUnderCursor.IsValid() && !IsSelectableAccordingToFocusMode(entityIdUnderCursor))
|
||||
{
|
||||
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
|
||||
mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down ||
|
||||
mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::DoubleClick)
|
||||
{
|
||||
m_invalidClicks->AddInvalidClick(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates);
|
||||
}
|
||||
|
||||
return CursorEntityIdQuery(AZ::EntityId(), AZ::EntityId());
|
||||
}
|
||||
|
||||
// Container Entity support - if the entity that is being selected is part of a closed container,
|
||||
// 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())
|
||||
{
|
||||
@@ -230,6 +243,12 @@ namespace AzToolsFramework
|
||||
return CursorEntityIdQuery(entityIdUnderCursor, AZ::EntityId());
|
||||
}
|
||||
|
||||
void EditorHelpers::Display2d(
|
||||
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
|
||||
{
|
||||
m_invalidClicks->Display2d(viewportInfo, debugDisplay);
|
||||
}
|
||||
|
||||
void EditorHelpers::DisplayHelpers(
|
||||
const AzFramework::ViewportInfo& viewportInfo,
|
||||
const AzFramework::CameraState& cameraState,
|
||||
@@ -291,19 +310,19 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorHelpers::IsSelectableInViewport(AZ::EntityId entityId)
|
||||
bool EditorHelpers::IsSelectableInViewport(const AZ::EntityId entityId) const
|
||||
{
|
||||
return IsSelectableAccordingToFocusMode(entityId) && IsSelectableAccordingToContainerEntities(entityId);
|
||||
}
|
||||
|
||||
bool EditorHelpers::IsSelectableAccordingToFocusMode(AZ::EntityId entityId)
|
||||
bool EditorHelpers::IsSelectableAccordingToFocusMode(const AZ::EntityId entityId) const
|
||||
{
|
||||
return m_focusModeInterface->IsInFocusSubTree(entityId);
|
||||
}
|
||||
|
||||
bool EditorHelpers::IsSelectableAccordingToContainerEntities(AZ::EntityId entityId)
|
||||
bool EditorHelpers::IsSelectableAccordingToContainerEntities(const AZ::EntityId entityId) const
|
||||
{
|
||||
if (ContainerEntityInterface* containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get())
|
||||
if (const auto* containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get())
|
||||
{
|
||||
return !containerEntityInterface->IsUnderClosedContainerEntity(entityId);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
#include <AzToolsFramework/ViewportSelection/InvalidClicks.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
@@ -80,20 +83,27 @@ namespace AzToolsFramework
|
||||
AzFramework::DebugDisplayRequests& debugDisplay,
|
||||
const AZStd::function<bool(AZ::EntityId)>& showIconCheck);
|
||||
|
||||
//! Handle 2d drawing for EditorHelper functionality.
|
||||
void Display2d(
|
||||
const AzFramework::ViewportInfo& viewportInfo,
|
||||
AzFramework::DebugDisplayRequests& debugDisplay);
|
||||
|
||||
//! 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);
|
||||
bool IsSelectableInViewport(AZ::EntityId entityId) const;
|
||||
|
||||
private:
|
||||
//! Returns whether the entityId can be selected in the viewport according
|
||||
//! to the current Editor Focus Mode setup.
|
||||
bool IsSelectableAccordingToFocusMode(AZ::EntityId entityId);
|
||||
bool IsSelectableAccordingToFocusMode(AZ::EntityId entityId) const;
|
||||
|
||||
//! Returns whether the entityId can be selected in the viewport according
|
||||
//! to the current Container Entityu setup.
|
||||
bool IsSelectableAccordingToContainerEntities(AZ::EntityId entityId);
|
||||
//! to the current Container Entity setup.
|
||||
bool IsSelectableAccordingToContainerEntities(AZ::EntityId entityId) const;
|
||||
|
||||
AZStd::unique_ptr<InvalidClicks> m_invalidClicks; //!< Display for invalid click behavior.
|
||||
|
||||
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers.
|
||||
const FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
const FocusModeInterface* m_focusModeInterface = nullptr; //!< API to interact with focus mode functionality.
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+51
-12
@@ -408,7 +408,7 @@ namespace AzToolsFramework
|
||||
const AzFramework::CameraState cameraState = GetCameraState(viewportId);
|
||||
for (size_t entityCacheIndex = 0; entityCacheIndex < entityDataCache.VisibleEntityDataCount(); ++entityCacheIndex)
|
||||
{
|
||||
if (entityDataCache.IsVisibleEntityLocked(entityCacheIndex) || !entityDataCache.IsVisibleEntityVisible(entityCacheIndex))
|
||||
if (!entityDataCache.IsVisibleEntitySelectableInViewport(entityCacheIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -3575,6 +3575,8 @@ namespace AzToolsFramework
|
||||
DrawAxisGizmo(viewportInfo, debugDisplay);
|
||||
|
||||
m_boxSelect.Display2d(viewportInfo, debugDisplay);
|
||||
|
||||
m_editorHelpers->Display2d(viewportInfo, debugDisplay);
|
||||
}
|
||||
|
||||
void EditorTransformComponentSelection::RefreshSelectedEntityIds()
|
||||
@@ -3678,26 +3680,63 @@ namespace AzToolsFramework
|
||||
void EditorTransformComponentSelection::OnEditorModeActivated(
|
||||
[[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode)
|
||||
{
|
||||
if (mode == ViewportEditorMode::Component)
|
||||
switch (mode)
|
||||
{
|
||||
SetAllViewportUiVisible(false);
|
||||
case ViewportEditorMode::Component:
|
||||
{
|
||||
SetAllViewportUiVisible(false);
|
||||
|
||||
EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect();
|
||||
EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect();
|
||||
ToolsApplicationNotificationBus::Handler::BusDisconnect();
|
||||
EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect();
|
||||
EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect();
|
||||
ToolsApplicationNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
break;
|
||||
case ViewportEditorMode::Focus:
|
||||
{
|
||||
ViewportUi::ViewportUiRequestBus::Event(
|
||||
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder, "Focus Mode");
|
||||
}
|
||||
break;
|
||||
case ViewportEditorMode::Default:
|
||||
case ViewportEditorMode::Pick:
|
||||
// noop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorTransformComponentSelection::OnEditorModeDeactivated(
|
||||
[[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode)
|
||||
const ViewportEditorModesInterface& editorModeState, const ViewportEditorMode mode)
|
||||
{
|
||||
if (mode == ViewportEditorMode::Component)
|
||||
switch (mode)
|
||||
{
|
||||
SetAllViewportUiVisible(true);
|
||||
case ViewportEditorMode::Component:
|
||||
{
|
||||
SetAllViewportUiVisible(true);
|
||||
|
||||
ToolsApplicationNotificationBus::Handler::BusConnect();
|
||||
EditorEntityVisibilityNotificationBus::Router::BusRouterConnect();
|
||||
EditorEntityLockComponentNotificationBus::Router::BusRouterConnect();
|
||||
ToolsApplicationNotificationBus::Handler::BusConnect();
|
||||
EditorEntityVisibilityNotificationBus::Router::BusRouterConnect();
|
||||
EditorEntityLockComponentNotificationBus::Router::BusRouterConnect();
|
||||
|
||||
// note: when leaving component mode, we check if we're still in focus mode (i.e. component mode was
|
||||
// started from within focus mode), if we are, ensure we create/update the viewport border (as leaving
|
||||
// component mode will attempt to remove it)
|
||||
if (editorModeState.IsModeActive(ViewportEditorMode::Focus))
|
||||
{
|
||||
ViewportUi::ViewportUiRequestBus::Event(
|
||||
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder, "Focus Mode");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ViewportEditorMode::Focus:
|
||||
{
|
||||
ViewportUi::ViewportUiRequestBus::Event(
|
||||
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RemoveViewportBorder);
|
||||
}
|
||||
break;
|
||||
case ViewportEditorMode::Default:
|
||||
case ViewportEditorMode::Pick:
|
||||
// noop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+109
-3
@@ -9,7 +9,9 @@
|
||||
#include "EditorVisibleEntityDataCache.h"
|
||||
|
||||
#include <AzCore/std/sort.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityModel.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
#include <Entity/EditorEntityHelpers.h>
|
||||
|
||||
@@ -21,13 +23,23 @@ namespace AzToolsFramework
|
||||
using ComponentEntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType;
|
||||
|
||||
EntityData() = default;
|
||||
EntityData(AZ::EntityId entityId, const AZ::Transform& worldFromLocal, bool locked, bool visible, bool selected, bool iconHidden);
|
||||
EntityData(
|
||||
AZ::EntityId entityId,
|
||||
const AZ::Transform& worldFromLocal,
|
||||
bool locked,
|
||||
bool visible,
|
||||
bool inFocus,
|
||||
bool descendantOfClosedContainer,
|
||||
bool selected,
|
||||
bool iconHidden);
|
||||
|
||||
AZ::Transform m_worldFromLocal;
|
||||
AZ::EntityId m_entityId;
|
||||
ComponentEntityAccentType m_accent = ComponentEntityAccentType::None;
|
||||
bool m_locked = false;
|
||||
bool m_visible = true;
|
||||
bool m_inFocus = true;
|
||||
bool m_descendantOfClosedContainer = false;
|
||||
bool m_selected = false;
|
||||
bool m_iconHidden = false;
|
||||
};
|
||||
@@ -57,12 +69,16 @@ namespace AzToolsFramework
|
||||
const AZ::Transform& worldFromLocal,
|
||||
const bool locked,
|
||||
const bool visible,
|
||||
const bool inFocus,
|
||||
const bool descendantOfClosedContainer,
|
||||
const bool selected,
|
||||
const bool iconHidden)
|
||||
: m_worldFromLocal(worldFromLocal)
|
||||
, m_entityId(entityId)
|
||||
, m_locked(locked)
|
||||
, m_visible(visible)
|
||||
, m_inFocus(inFocus)
|
||||
, m_descendantOfClosedContainer(descendantOfClosedContainer)
|
||||
, m_selected(selected)
|
||||
, m_iconHidden(iconHidden)
|
||||
{
|
||||
@@ -106,6 +122,18 @@ namespace AzToolsFramework
|
||||
bool locked = false;
|
||||
EditorEntityInfoRequestBus::EventResult(locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked);
|
||||
|
||||
bool inFocus = false;
|
||||
if (auto focusModeInterface = AZ::Interface<FocusModeInterface>::Get())
|
||||
{
|
||||
inFocus = focusModeInterface->IsInFocusSubTree(entityId);
|
||||
}
|
||||
|
||||
bool descendantOfClosedContainer = false;
|
||||
if (ContainerEntityInterface* containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get())
|
||||
{
|
||||
descendantOfClosedContainer = containerEntityInterface->IsUnderClosedContainerEntity(entityId);
|
||||
}
|
||||
|
||||
bool iconHidden = false;
|
||||
EditorEntityIconComponentRequestBus::EventResult(
|
||||
iconHidden, entityId, &EditorEntityIconComponentRequests::IsEntityIconHiddenInViewport);
|
||||
@@ -113,7 +141,7 @@ namespace AzToolsFramework
|
||||
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
|
||||
|
||||
return { entityId, worldFromLocal, locked, visible, IsSelected(entityId), iconHidden };
|
||||
return { entityId, worldFromLocal, locked, visible, inFocus, descendantOfClosedContainer, IsSelected(entityId), iconHidden };
|
||||
}
|
||||
|
||||
EditorVisibleEntityDataCache::EditorVisibleEntityDataCache()
|
||||
@@ -126,10 +154,17 @@ namespace AzToolsFramework
|
||||
EntitySelectionEvents::Bus::Router::BusRouterConnect();
|
||||
EditorEntityIconComponentNotificationBus::Router::BusRouterConnect();
|
||||
ToolsApplicationNotificationBus::Handler::BusConnect();
|
||||
|
||||
AzFramework::EntityContextId editorEntityContextId = AzToolsFramework::GetEntityContextId();
|
||||
|
||||
ContainerEntityNotificationBus::Handler::BusConnect(editorEntityContextId);
|
||||
FocusModeNotificationBus::Handler::BusConnect(editorEntityContextId);
|
||||
}
|
||||
|
||||
EditorVisibleEntityDataCache::~EditorVisibleEntityDataCache()
|
||||
{
|
||||
FocusModeNotificationBus::Handler::BusDisconnect();
|
||||
ContainerEntityNotificationBus::Handler::BusDisconnect();
|
||||
ToolsApplicationNotificationBus::Handler::BusDisconnect();
|
||||
EditorEntityIconComponentNotificationBus::Router::BusRouterDisconnect();
|
||||
EntitySelectionEvents::Bus::Router::BusRouterDisconnect();
|
||||
@@ -260,7 +295,10 @@ namespace AzToolsFramework
|
||||
|
||||
bool EditorVisibleEntityDataCache::IsVisibleEntitySelectableInViewport(size_t index) const
|
||||
{
|
||||
return m_impl->m_visibleEntityDatas[index].m_visible && !m_impl->m_visibleEntityDatas[index].m_locked;
|
||||
return m_impl->m_visibleEntityDatas[index].m_visible
|
||||
&& !m_impl->m_visibleEntityDatas[index].m_locked
|
||||
&& m_impl->m_visibleEntityDatas[index].m_inFocus
|
||||
&& !m_impl->m_visibleEntityDatas[index].m_descendantOfClosedContainer;
|
||||
}
|
||||
|
||||
AZStd::optional<size_t> EditorVisibleEntityDataCache::GetVisibleEntityIndexFromId(const AZ::EntityId entityId) const
|
||||
@@ -371,4 +409,72 @@ namespace AzToolsFramework
|
||||
m_impl->m_visibleEntityDatas[entityIndex.value()].m_iconHidden = iconHidden;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorVisibleEntityDataCache::OnContainerEntityStatusChanged(AZ::EntityId entityId, [[maybe_unused]] bool open)
|
||||
{
|
||||
// Get container descendants
|
||||
AzToolsFramework::EntityIdList descendantIds;
|
||||
AZ::TransformBus::EventResult(descendantIds, entityId, &AZ::TransformBus::Events::GetAllDescendants);
|
||||
|
||||
// Update cached values
|
||||
if (auto containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get())
|
||||
{
|
||||
for (AZ::EntityId descendantId : descendantIds)
|
||||
{
|
||||
if (AZStd::optional<size_t> entityIndex = GetVisibleEntityIndexFromId(descendantId))
|
||||
{
|
||||
m_impl->m_visibleEntityDatas[entityIndex.value()].m_descendantOfClosedContainer =
|
||||
containerEntityInterface->IsUnderClosedContainerEntity(descendantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorVisibleEntityDataCache::OnEditorFocusChanged(AZ::EntityId previousFocusEntityId, AZ::EntityId newFocusEntityId)
|
||||
{
|
||||
if (previousFocusEntityId.IsValid() && newFocusEntityId.IsValid())
|
||||
{
|
||||
// Get previous focus root descendants
|
||||
AzToolsFramework::EntityIdList previousDescendantIds;
|
||||
AZ::TransformBus::EventResult(previousDescendantIds, previousFocusEntityId, &AZ::TransformBus::Events::GetAllDescendants);
|
||||
|
||||
// Get new focus root descendants
|
||||
AzToolsFramework::EntityIdList newDescendantIds;
|
||||
AZ::TransformBus::EventResult(newDescendantIds, newFocusEntityId, &AZ::TransformBus::Events::GetAllDescendants);
|
||||
|
||||
// Merge EntityId Lists to avoid refreshing values twice
|
||||
AzToolsFramework::EntityIdSet descendantsSet;
|
||||
descendantsSet.insert(previousFocusEntityId);
|
||||
descendantsSet.insert(newFocusEntityId);
|
||||
descendantsSet.insert(previousDescendantIds.begin(), previousDescendantIds.end());
|
||||
descendantsSet.insert(newDescendantIds.begin(), newDescendantIds.end());
|
||||
|
||||
// Update cached values
|
||||
if (auto focusModeInterface = AZ::Interface<FocusModeInterface>::Get())
|
||||
{
|
||||
for (const AZ::EntityId& descendantId : descendantsSet)
|
||||
{
|
||||
if (AZStd::optional<size_t> entityIndex = GetVisibleEntityIndexFromId(descendantId))
|
||||
{
|
||||
m_impl->m_visibleEntityDatas[entityIndex.value()].m_inFocus = focusModeInterface->IsInFocusSubTree(descendantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If either focus was the invalid entity, refresh all entities.
|
||||
if (auto focusModeInterface = AZ::Interface<FocusModeInterface>::Get())
|
||||
{
|
||||
for (size_t entityIndex = 0; entityIndex < m_impl->m_visibleEntityDatas.size(); ++entityIndex)
|
||||
{
|
||||
if (AZ::EntityId descendantId = GetVisibleEntityId(entityIndex); descendantId.IsValid())
|
||||
{
|
||||
m_impl->m_visibleEntityDatas[entityIndex].m_inFocus = focusModeInterface->IsInFocusSubTree(descendantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+17
-7
@@ -11,6 +11,8 @@
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeNotificationBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorEntityIconComponentBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorLockComponentBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorSelectionAccentSystemComponent.h>
|
||||
@@ -28,6 +30,8 @@ namespace AzToolsFramework
|
||||
, private EntitySelectionEvents::Bus::Router
|
||||
, private EditorEntityIconComponentNotificationBus::Router
|
||||
, private ToolsApplicationNotificationBus::Handler
|
||||
, private ContainerEntityNotificationBus::Handler
|
||||
, private FocusModeNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
EditorVisibleEntityDataCache();
|
||||
@@ -58,28 +62,34 @@ namespace AzToolsFramework
|
||||
void AddEntityIds(const EntityIdList& entityIds);
|
||||
|
||||
private:
|
||||
// ToolsApplicationNotificationBus
|
||||
// ToolsApplicationNotificationBus overrides ...
|
||||
void AfterUndoRedo() override;
|
||||
|
||||
// EditorEntityVisibilityNotificationBus
|
||||
// EditorEntityVisibilityNotificationBus overrides ...
|
||||
void OnEntityVisibilityChanged(bool visibility) override;
|
||||
|
||||
// EditorEntityLockComponentNotificationBus
|
||||
// EditorEntityLockComponentNotificationBus overrides ...
|
||||
void OnEntityLockChanged(bool locked) override;
|
||||
|
||||
// TransformNotificationBus
|
||||
// TransformNotificationBus overrides ...
|
||||
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
|
||||
|
||||
// EditorComponentSelectionNotificationsBus
|
||||
// EditorComponentSelectionNotificationsBus overrides ...
|
||||
void OnAccentTypeChanged(EntityAccentType accent) override;
|
||||
|
||||
// EntitySelectionEvents::Bus
|
||||
// EntitySelectionEvents::Bus overrides ...
|
||||
void OnSelected() override;
|
||||
void OnDeselected() override;
|
||||
|
||||
// EditorEntityIconComponentNotificationBus
|
||||
// EditorEntityIconComponentNotificationBus overrides ...
|
||||
void OnEntityIconChanged(const AZ::Data::AssetId& entityIconAssetId) override;
|
||||
|
||||
// ContainerEntityNotificationBus overrides ...
|
||||
void OnContainerEntityStatusChanged(AZ::EntityId entityId, bool open) override;
|
||||
|
||||
// FocusModeNotificationBus overrides ...
|
||||
void OnEditorFocusChanged(AZ::EntityId previousFocusEntityId, AZ::EntityId newFocusEntityId) override;
|
||||
|
||||
class EditorVisibleEntityDataCacheImpl;
|
||||
AZStd::unique_ptr<EditorVisibleEntityDataCacheImpl> m_impl; //!< Internal representation of entity data cache.
|
||||
};
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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/Console/Console.h>
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
|
||||
#include <AzToolsFramework/ViewportSelection/InvalidClicks.h>
|
||||
|
||||
AZ_CVAR(float, ed_invalidClickRadius, 10.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum invalid click radius to expand to");
|
||||
AZ_CVAR(float, ed_invalidClickDuration, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Duration to display the invalid click feedback");
|
||||
AZ_CVAR(float, ed_invalidClickMessageSize, 0.8f, nullptr, AZ::ConsoleFunctorFlags::Null, "Size of text for invalid message");
|
||||
AZ_CVAR(
|
||||
float,
|
||||
ed_invalidClickMessageVerticalOffset,
|
||||
30.0f,
|
||||
nullptr,
|
||||
AZ::ConsoleFunctorFlags::Null,
|
||||
"Vertical offset from cursor of invalid click message");
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
void ExpandingFadingCircles::Begin(const AzFramework::ScreenPoint& screenPoint)
|
||||
{
|
||||
FadingCircle fadingCircle;
|
||||
fadingCircle.m_position = screenPoint;
|
||||
fadingCircle.m_opacity = 1.0f;
|
||||
fadingCircle.m_radius = 0.0f;
|
||||
m_fadingCircles.push_back(fadingCircle);
|
||||
}
|
||||
|
||||
void ExpandingFadingCircles::Update(const float deltaTime)
|
||||
{
|
||||
for (auto& fadingCircle : m_fadingCircles)
|
||||
{
|
||||
fadingCircle.m_opacity = AZStd::max(fadingCircle.m_opacity - (deltaTime / ed_invalidClickDuration), 0.0f);
|
||||
fadingCircle.m_radius += deltaTime * ed_invalidClickRadius;
|
||||
}
|
||||
|
||||
m_fadingCircles.erase(
|
||||
AZStd::remove_if(
|
||||
m_fadingCircles.begin(), m_fadingCircles.end(),
|
||||
[](const FadingCircle& fadingCircle)
|
||||
{
|
||||
return fadingCircle.m_opacity <= 0.0f;
|
||||
}),
|
||||
m_fadingCircles.end());
|
||||
}
|
||||
|
||||
bool ExpandingFadingCircles::Updating()
|
||||
{
|
||||
return !m_fadingCircles.empty();
|
||||
}
|
||||
|
||||
void ExpandingFadingCircles::Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
|
||||
{
|
||||
const AZ::Vector2 viewportSize = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId).m_viewportSize;
|
||||
|
||||
for (const auto& fadingCircle : m_fadingCircles)
|
||||
{
|
||||
const auto position = AzFramework::Vector2FromScreenPoint(fadingCircle.m_position) / viewportSize;
|
||||
debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, fadingCircle.m_opacity));
|
||||
debugDisplay.DrawWireCircle2d(position, fadingCircle.m_radius * 0.005f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void FadingText::Begin(const AzFramework::ScreenPoint& screenPoint)
|
||||
{
|
||||
m_opacity = 1.0f;
|
||||
m_invalidClickPosition = screenPoint;
|
||||
}
|
||||
|
||||
void FadingText::Update(const float deltaTime)
|
||||
{
|
||||
m_opacity -= deltaTime / ed_invalidClickDuration;
|
||||
}
|
||||
|
||||
bool FadingText::Updating()
|
||||
{
|
||||
return m_opacity >= 0.0f;
|
||||
}
|
||||
|
||||
void FadingText::Display(
|
||||
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
|
||||
{
|
||||
if (constexpr float MinOpacity = 0.05f; m_opacity >= MinOpacity)
|
||||
{
|
||||
debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, m_opacity));
|
||||
debugDisplay.Draw2dTextLabel(
|
||||
aznumeric_cast<float>(m_invalidClickPosition.m_x),
|
||||
aznumeric_cast<float>(m_invalidClickPosition.m_y) - ed_invalidClickMessageVerticalOffset, ed_invalidClickMessageSize,
|
||||
m_message.c_str(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void InvalidClicks::AddInvalidClick(const AzFramework::ScreenPoint& screenPoint)
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
|
||||
for (auto& invalidClickBehavior : m_invalidClickBehaviors)
|
||||
{
|
||||
invalidClickBehavior->Begin(screenPoint);
|
||||
}
|
||||
}
|
||||
|
||||
void InvalidClicks::OnTick(const float deltaTime, [[maybe_unused]] const AZ::ScriptTimePoint time)
|
||||
{
|
||||
for (auto& invalidClickBehavior : m_invalidClickBehaviors)
|
||||
{
|
||||
invalidClickBehavior->Update(deltaTime);
|
||||
}
|
||||
|
||||
const auto updating = AZStd::any_of(
|
||||
m_invalidClickBehaviors.begin(), m_invalidClickBehaviors.end(),
|
||||
[](const auto& invalidClickBehavior)
|
||||
{
|
||||
return invalidClickBehavior->Updating();
|
||||
});
|
||||
|
||||
if (!updating && AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void InvalidClicks::Display2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
|
||||
{
|
||||
debugDisplay.DepthTestOff();
|
||||
|
||||
for (const auto& invalidClickBehavior : m_invalidClickBehaviors)
|
||||
{
|
||||
invalidClickBehavior->Display(viewportInfo, debugDisplay);
|
||||
}
|
||||
|
||||
debugDisplay.DepthTestOn();
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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/TickBus.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class DebugDisplayRequests;
|
||||
struct ViewportInfo;
|
||||
} // namespace AzFramework
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace ViewportInteraction
|
||||
{
|
||||
struct MouseInteractionEvent;
|
||||
}
|
||||
|
||||
//! An interface to provide invalid click feedback in the editor viewport.
|
||||
class InvalidClick
|
||||
{
|
||||
public:
|
||||
virtual ~InvalidClick() = default;
|
||||
|
||||
//! Begin the feedback.
|
||||
//! @param screenPoint The position of the click in screen coordinates.
|
||||
virtual void Begin(const AzFramework::ScreenPoint& screenPoint) = 0;
|
||||
//! Update the invalid click feedback
|
||||
virtual void Update(float deltaTime) = 0;
|
||||
//! Report if the click feedback is running or not (returning false will signal the TickBus can be disconnected from).
|
||||
virtual bool Updating() = 0;
|
||||
//! Display the click feedback in the viewport.
|
||||
virtual void Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) = 0;
|
||||
};
|
||||
|
||||
//! Display expanding fading circles for every click of the mouse that is invalid.
|
||||
class ExpandingFadingCircles : public InvalidClick
|
||||
{
|
||||
public:
|
||||
void Begin(const AzFramework::ScreenPoint& screenPoint) override;
|
||||
void Update(float deltaTime) override;
|
||||
bool Updating() override;
|
||||
void Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override;
|
||||
|
||||
private:
|
||||
//! Stores a circle representation with a lifetime to grow and fade out over time.
|
||||
struct FadingCircle
|
||||
{
|
||||
AzFramework::ScreenPoint m_position;
|
||||
float m_radius;
|
||||
float m_opacity;
|
||||
};
|
||||
|
||||
using FadingCircles = AZStd::vector<FadingCircle>;
|
||||
FadingCircles m_fadingCircles; //!< Collection of fading circles to draw for clicks that have no effect.
|
||||
};
|
||||
|
||||
//! Display fading text where an invalid click happened.
|
||||
//! @note There is only one fading text, each click will update its position.
|
||||
class FadingText : public InvalidClick
|
||||
{
|
||||
public:
|
||||
explicit FadingText(AZStd::string message)
|
||||
: m_message(AZStd::move(message))
|
||||
{
|
||||
}
|
||||
|
||||
void Begin(const AzFramework::ScreenPoint& screenPoint) override;
|
||||
void Update(float deltaTime) override;
|
||||
bool Updating() override;
|
||||
void Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override;
|
||||
|
||||
private:
|
||||
AZStd::string m_message; //!< Message to display for fading text.
|
||||
float m_opacity = 1.0f; //!< The opacity of the invalid click message.
|
||||
AzFramework::ScreenPoint m_invalidClickPosition; //!< The position to display the invalid click message.
|
||||
};
|
||||
|
||||
//! Interface to begin invalid click feedback (will run all added InvalidClick behaviors).
|
||||
class InvalidClicks : private AZ::TickBus::Handler
|
||||
{
|
||||
public:
|
||||
explicit InvalidClicks(AZStd::vector<AZStd::unique_ptr<InvalidClick>> invalidClickBehaviors)
|
||||
: m_invalidClickBehaviors(AZStd::move(invalidClickBehaviors))
|
||||
{
|
||||
}
|
||||
|
||||
//! Add an invalid click and activate one or more of the added invalid click behaviors.
|
||||
void AddInvalidClick(const AzFramework::ScreenPoint& screenPoint);
|
||||
|
||||
//! Handle 2d drawing for EditorHelper functionality.
|
||||
void Display2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay);
|
||||
|
||||
private:
|
||||
//! AZ::TickBus overrides ...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
AZStd::vector<AZStd::unique_ptr<InvalidClick>> m_invalidClickBehaviors; //!< Invalid click behaviors to run.
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
@@ -290,9 +290,9 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
return false;
|
||||
}
|
||||
|
||||
void ViewportUiDisplay::CreateComponentModeBorder(const AZStd::string& borderTitle)
|
||||
void ViewportUiDisplay::CreateViewportBorder(const AZStd::string& borderTitle)
|
||||
{
|
||||
AZStd::string styleSheet = AZStd::string::format(
|
||||
const AZStd::string styleSheet = AZStd::string::format(
|
||||
"border: %dpx solid %s; border-top: %dpx solid %s;", HighlightBorderSize, HighlightBorderColor, TopHighlightBorderSize,
|
||||
HighlightBorderColor);
|
||||
m_uiOverlay.setStyleSheet(styleSheet.c_str());
|
||||
@@ -303,7 +303,7 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
m_componentModeBorderText.setText(borderTitle.c_str());
|
||||
}
|
||||
|
||||
void ViewportUiDisplay::RemoveComponentModeBorder()
|
||||
void ViewportUiDisplay::RemoveViewportBorder()
|
||||
{
|
||||
m_componentModeBorderText.setVisible(false);
|
||||
m_uiOverlay.setStyleSheet("border: none;");
|
||||
@@ -420,6 +420,7 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
m_uiMainWindow.setVisible(true);
|
||||
m_uiOverlay.setVisible(true);
|
||||
}
|
||||
|
||||
m_uiMainWindow.setMask(region);
|
||||
}
|
||||
|
||||
@@ -437,6 +438,7 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
{
|
||||
return element->second;
|
||||
}
|
||||
|
||||
return ViewportUiElementInfo{ nullptr, InvalidViewportUiElementId, false };
|
||||
}
|
||||
|
||||
|
||||
@@ -89,8 +89,8 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
AZStd::shared_ptr<QWidget> GetViewportUiElement(ViewportUiElementId elementId);
|
||||
bool IsViewportUiElementVisible(ViewportUiElementId elementId);
|
||||
|
||||
void CreateComponentModeBorder(const AZStd::string& borderTitle);
|
||||
void RemoveComponentModeBorder();
|
||||
void CreateViewportBorder(const AZStd::string& borderTitle);
|
||||
void RemoveViewportBorder();
|
||||
|
||||
private:
|
||||
void PrepareWidgetForViewportUi(QPointer<QWidget> widget);
|
||||
|
||||
@@ -240,14 +240,14 @@ namespace AzToolsFramework::ViewportUi
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportUiManager::CreateComponentModeBorder(const AZStd::string& borderTitle)
|
||||
void ViewportUiManager::CreateViewportBorder(const AZStd::string& borderTitle)
|
||||
{
|
||||
m_viewportUi->CreateComponentModeBorder(borderTitle);
|
||||
m_viewportUi->CreateViewportBorder(borderTitle);
|
||||
}
|
||||
|
||||
void ViewportUiManager::RemoveComponentModeBorder()
|
||||
void ViewportUiManager::RemoveViewportBorder()
|
||||
{
|
||||
m_viewportUi->RemoveComponentModeBorder();
|
||||
m_viewportUi->RemoveViewportBorder();
|
||||
}
|
||||
|
||||
void ViewportUiManager::PressButton(ClusterId clusterId, ButtonId buttonId)
|
||||
|
||||
@@ -50,8 +50,8 @@ namespace AzToolsFramework::ViewportUi
|
||||
void RegisterTextFieldCallback(TextFieldId textFieldId, AZ::Event<AZStd::string>::Handler& handler) override;
|
||||
void RemoveTextField(TextFieldId textFieldId) override;
|
||||
void SetTextFieldVisible(TextFieldId textFieldId, bool visible) override;
|
||||
void CreateComponentModeBorder(const AZStd::string& borderTitle) override;
|
||||
void RemoveComponentModeBorder() override;
|
||||
void CreateViewportBorder(const AZStd::string& borderTitle) override;
|
||||
void RemoveViewportBorder() override;
|
||||
void PressButton(ClusterId clusterId, ButtonId buttonId) override;
|
||||
void PressButton(SwitcherId switcherId, ButtonId buttonId) override;
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace AzToolsFramework::ViewportUi
|
||||
virtual void RegisterSwitcherEventHandler(SwitcherId switcherId, AZ::Event<ButtonId>::Handler& handler) = 0;
|
||||
//! Removes a cluster from the Viewport UI system.
|
||||
virtual void RemoveCluster(ClusterId clusterId) = 0;
|
||||
//!
|
||||
//! Removes a switcher from the Viewport UI system.
|
||||
virtual void RemoveSwitcher(SwitcherId switcherId) = 0;
|
||||
//! Sets the visibility of the cluster.
|
||||
virtual void SetClusterVisible(ClusterId clusterId, bool visible) = 0;
|
||||
@@ -96,12 +96,12 @@ namespace AzToolsFramework::ViewportUi
|
||||
//! Sets the visibility of the text field.
|
||||
virtual void SetTextFieldVisible(TextFieldId textFieldId, bool visible) = 0;
|
||||
//! Create the highlight border for Component Mode.
|
||||
virtual void CreateComponentModeBorder(const AZStd::string& borderTitle) = 0;
|
||||
virtual void CreateViewportBorder(const AZStd::string& borderTitle) = 0;
|
||||
//! Remove the highlight border for Component Mode.
|
||||
virtual void RemoveComponentModeBorder() = 0;
|
||||
//! Invoke a button press in a cluster.
|
||||
virtual void RemoveViewportBorder() = 0;
|
||||
//! Invoke a button press on a cluster.
|
||||
virtual void PressButton(ClusterId clusterId, ButtonId buttonId) = 0;
|
||||
//!
|
||||
//! Invoke a button press on a switcher.
|
||||
virtual void PressButton(SwitcherId switcherId, ButtonId buttonId) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -553,6 +553,8 @@ set(FILES
|
||||
ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp
|
||||
ViewportSelection/EditorVisibleEntityDataCache.h
|
||||
ViewportSelection/EditorVisibleEntityDataCache.cpp
|
||||
ViewportSelection/InvalidClicks.h
|
||||
ViewportSelection/InvalidClicks.cpp
|
||||
ViewportSelection/ViewportEditorModeTracker.cpp
|
||||
ViewportSelection/ViewportEditorModeTracker.h
|
||||
ToolsFileUtils/ToolsFileUtils.h
|
||||
@@ -646,6 +648,9 @@ 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
|
||||
|
||||
Reference in New Issue
Block a user