Merge branch 'development' into math_string_converters
This commit is contained in:
+3
-4
@@ -21,7 +21,6 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetEntryChangeset.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/FolderThumbnail.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/ProductThumbnail.h>
|
||||
@@ -71,9 +70,9 @@ namespace AzToolsFramework
|
||||
AssetBrowserInteractionNotificationBus::Handler::BusConnect();
|
||||
|
||||
using namespace Thumbnailer;
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(FolderThumbnailCache), ThumbnailContext::DefaultContext);
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SourceThumbnailCache), ThumbnailContext::DefaultContext);
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(ProductThumbnailCache), ThumbnailContext::DefaultContext);
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(FolderThumbnailCache));
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SourceThumbnailCache));
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(ProductThumbnailCache));
|
||||
|
||||
AzFramework::SocketConnection* socketConn = AzFramework::SocketConnection::GetInstance();
|
||||
AZ_Assert(socketConn, "AzToolsFramework::AssetBrowser::AssetBrowserComponent requires a valid socket conection!");
|
||||
|
||||
+11
-4
@@ -82,7 +82,7 @@ namespace AzToolsFramework
|
||||
});
|
||||
connect(m_ui->m_assetBrowserTreeViewWidget, &QAbstractItemView::doubleClicked, this, &AssetPickerDialog::DoubleClickedSlot);
|
||||
connect(m_ui->m_assetBrowserTreeViewWidget, &AssetBrowserTreeView::selectionChangedSignal, this,
|
||||
[this](const QItemSelection&, const QItemSelection&){ AssetPickerDialog::SelectionChangedSlot(); });
|
||||
[this](const QItemSelection&, const QItemSelection&){ SelectionChangedSlot(); });
|
||||
connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace AzToolsFramework
|
||||
m_ui->m_assetBrowserTableViewWidget, &AssetBrowserTableView::selectionChangedSignal, this,
|
||||
[this](const QItemSelection&, const QItemSelection&)
|
||||
{
|
||||
AssetPickerDialog::SelectionChangedSlot();
|
||||
SelectionChangedSlot();
|
||||
});
|
||||
|
||||
connect(m_ui->m_assetBrowserTableViewWidget, &QAbstractItemView::doubleClicked, this, &AssetPickerDialog::DoubleClickedSlot);
|
||||
@@ -174,8 +174,15 @@ namespace AzToolsFramework
|
||||
m_tableModel->UpdateTableModelMaps();
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, &AssetPickerDialog::RestoreState);
|
||||
SelectionChangedSlot();
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
RestoreState();
|
||||
|
||||
// The selection doesn't propagate immediately, so we need to delay
|
||||
// it as well so that the OK button can be updated appropriately.
|
||||
// Otherwise, it will always be disabled when you first launch
|
||||
// the asset picker dialog.
|
||||
SelectionChangedSlot();
|
||||
});
|
||||
}
|
||||
|
||||
AssetPickerDialog::~AssetPickerDialog() = default;
|
||||
|
||||
+3
-3
@@ -58,16 +58,16 @@ namespace AzToolsFramework
|
||||
void keyPressEvent(QKeyEvent* e) override;
|
||||
void resizeEvent(QResizeEvent* resizeEvent) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
protected Q_SLOTS:
|
||||
void DoubleClickedSlot(const QModelIndex& index);
|
||||
void SelectionChangedSlot();
|
||||
void RestoreState();
|
||||
void OnFilterUpdated();
|
||||
|
||||
private:
|
||||
protected:
|
||||
//! Evaluate whether current selection is valid.
|
||||
//! Valid selection requires exactly one item to be selected, must be source or product type, and must match the wildcard filter
|
||||
bool EvaluateSelection() const;
|
||||
virtual bool EvaluateSelection() const;
|
||||
void UpdatePreview() const;
|
||||
void SaveState();
|
||||
|
||||
|
||||
+3
-1
@@ -75,7 +75,9 @@ namespace AzToolsFramework
|
||||
bool foundIt = false;
|
||||
AZStd::string watchFolder;
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, iconPath.toUtf8().constData(), assetInfo, watchFolder);
|
||||
AssetSystemRequestBus::BroadcastResult(
|
||||
foundIt, &AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, iconPath.toUtf8().constData(), assetInfo,
|
||||
watchFolder);
|
||||
|
||||
if (foundIt)
|
||||
{
|
||||
|
||||
+2
-1
@@ -67,7 +67,8 @@ namespace AzToolsFramework
|
||||
bool foundIt = false;
|
||||
AZStd::string watchFolder;
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
AssetSystemRequestBus::BroadcastResult(foundIt, &AssetSystemRequestBus::Events::GetSourceInfoBySourceUUID, sourceKey->GetSourceUuid(), assetInfo, watchFolder);
|
||||
AssetSystemRequestBus::BroadcastResult(
|
||||
foundIt, &AssetSystemRequestBus::Events::GetSourceInfoBySourceUUID, sourceKey->GetSourceUuid(), assetInfo, watchFolder);
|
||||
|
||||
QString iconPathToUse;
|
||||
if (foundIt)
|
||||
|
||||
-5
@@ -203,11 +203,6 @@ namespace AzToolsFramework
|
||||
return selectionModel()->selectedIndexes();
|
||||
}
|
||||
|
||||
void AssetBrowserTreeView::SetThumbnailContext(const char* thumbnailContext) const
|
||||
{
|
||||
m_delegate->SetThumbnailContext(thumbnailContext);
|
||||
}
|
||||
|
||||
void AssetBrowserTreeView::SetShowSourceControlIcons(bool showSourceControlsIcons)
|
||||
{
|
||||
m_delegate->SetShowSourceControlIcons(showSourceControlsIcons);
|
||||
|
||||
-1
@@ -73,7 +73,6 @@ namespace AzToolsFramework
|
||||
void OnAssetBrowserComponentReady() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SetThumbnailContext(const char* context) const;
|
||||
void SetShowSourceControlIcons(bool showSourceControlsIcons);
|
||||
void UpdateAfterFilter(bool hasFilter, bool selectFirstValidEntry);
|
||||
|
||||
|
||||
+2
-7
@@ -112,11 +112,6 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void EntryDelegate::SetThumbnailContext(const char* thumbnailContext)
|
||||
{
|
||||
m_thumbnailContext = thumbnailContext;
|
||||
}
|
||||
|
||||
void EntryDelegate::SetShowSourceControlIcons(bool showSourceControl)
|
||||
{
|
||||
m_showSourceControl = showSourceControl;
|
||||
@@ -125,8 +120,8 @@ namespace AzToolsFramework
|
||||
int EntryDelegate::DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const
|
||||
{
|
||||
SharedThumbnail thumbnail;
|
||||
ThumbnailerRequestsBus::BroadcastResult(thumbnail, &ThumbnailerRequests::GetThumbnail, thumbnailKey, m_thumbnailContext.c_str());
|
||||
AZ_Assert(thumbnail, "The shared numbernail was not available from the ThumbnailerRequestsBus.");
|
||||
ThumbnailerRequestBus::BroadcastResult(thumbnail, &ThumbnailerRequests::GetThumbnail, thumbnailKey);
|
||||
AZ_Assert(thumbnail, "The shared numbernail was not available from the ThumbnailerRequestBus.");
|
||||
AZ_Assert(painter, "A null QPainter was passed in to DrawThumbnail.");
|
||||
if (!painter || !thumbnail || thumbnail->GetState() == Thumbnail::State::Failed)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/function/function_fwd.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer<QBrushData,QBrushDataPointerDeleter>' needs to have dll-interface to be used by clients of class 'QBrush'
|
||||
// 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning)
|
||||
#include <QStyledItemDelegate>
|
||||
@@ -50,14 +49,11 @@ namespace AzToolsFramework
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
//! Set location where thumbnails are located for this instance of asset browser
|
||||
void SetThumbnailContext(const char* thumbnailContext);
|
||||
//! Set whether to show source control icons, this is still temporary mainly to support existing functionality of material browser
|
||||
void SetShowSourceControlIcons(bool showSourceControl);
|
||||
|
||||
protected:
|
||||
int m_iconSize;
|
||||
AZStd::string m_thumbnailContext = ThumbnailContext::DefaultContext;
|
||||
bool m_showSourceControl = false;
|
||||
//! Draw a thumbnail and return its width
|
||||
int DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const;
|
||||
|
||||
+38
-28
@@ -14,6 +14,8 @@
|
||||
#include <AzToolsFramework/Manipulators/ManipulatorSnapping.h>
|
||||
#include <AzFramework/Viewport/ViewportColors.h>
|
||||
#include <AzFramework/Viewport/ViewportConstants.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Component/NonUniformScaleBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -37,20 +39,20 @@ namespace AzToolsFramework
|
||||
void BoxViewportEdit::UpdateManipulators()
|
||||
{
|
||||
AZ::Transform boxWorldFromLocal = AZ::Transform::CreateIdentity();
|
||||
BoxManipulatorRequestBus::EventResult(
|
||||
boxWorldFromLocal, m_entityComponentIdPair, &BoxManipulatorRequests::GetCurrentTransform);
|
||||
AZ::TransformBus::EventResult(
|
||||
boxWorldFromLocal, m_entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
|
||||
|
||||
AZ::Vector3 boxScale = AZ::Vector3::CreateOne();
|
||||
BoxManipulatorRequestBus::EventResult(
|
||||
boxScale, m_entityComponentIdPair, &BoxManipulatorRequests::GetBoxScale);
|
||||
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
|
||||
AZ::NonUniformScaleRequestBus::EventResult(
|
||||
nonUniformScale, m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequestBus::Events::GetScale);
|
||||
|
||||
AZ::Vector3 boxDimensions = AZ::Vector3::CreateZero();
|
||||
BoxManipulatorRequestBus::EventResult(
|
||||
boxDimensions, m_entityComponentIdPair, &BoxManipulatorRequests::GetDimensions);
|
||||
boxDimensions, m_entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetDimensions);
|
||||
|
||||
// ensure we apply the entity scale to the box dimensions so
|
||||
// the manipulators appear in the correct location
|
||||
boxDimensions *= boxScale;
|
||||
AZ::Transform boxLocalTransform = AZ::Transform::CreateIdentity();
|
||||
BoxManipulatorRequestBus::EventResult(
|
||||
boxLocalTransform, m_entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetCurrentLocalTransform);
|
||||
|
||||
for (size_t manipulatorIndex = 0; manipulatorIndex < m_linearManipulators.size(); ++manipulatorIndex)
|
||||
{
|
||||
@@ -58,7 +60,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
linearManipulator->SetSpace(boxWorldFromLocal);
|
||||
linearManipulator->SetLocalTransform(
|
||||
AZ::Transform::CreateTranslation(s_boxAxes[manipulatorIndex] * 0.5f * boxDimensions));
|
||||
boxLocalTransform * AZ::Transform::CreateTranslation(s_boxAxes[manipulatorIndex] * 0.5f * boxDimensions));
|
||||
linearManipulator->SetNonUniformScale(nonUniformScale);
|
||||
linearManipulator->SetBoundsDirty();
|
||||
}
|
||||
}
|
||||
@@ -69,8 +72,8 @@ namespace AzToolsFramework
|
||||
m_entityComponentIdPair = entityComponentIdPair;
|
||||
|
||||
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
|
||||
BoxManipulatorRequestBus::EventResult(
|
||||
worldFromLocal, entityComponentIdPair, &BoxManipulatorRequests::GetCurrentTransform);
|
||||
AZ::TransformBus::EventResult(
|
||||
worldFromLocal, entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
|
||||
|
||||
for (size_t manipulatorIndex = 0; manipulatorIndex < m_linearManipulators.size(); ++manipulatorIndex)
|
||||
{
|
||||
@@ -85,36 +88,35 @@ namespace AzToolsFramework
|
||||
|
||||
ManipulatorViews views;
|
||||
views.emplace_back(CreateManipulatorViewQuadBillboard(
|
||||
AzFramework::ViewportColors::DefaultManipulatorHandleColor, AzFramework::ViewportConstants::DefaultManipulatorHandleSize));
|
||||
AzFramework::ViewportColors::DefaultManipulatorHandleColor,
|
||||
AzFramework::ViewportConstants::DefaultManipulatorHandleSize));
|
||||
linearManipulator->SetViews(AZStd::move(views));
|
||||
|
||||
linearManipulator->InstallMouseMoveCallback(
|
||||
[this, entityComponentIdPair](
|
||||
const LinearManipulator::Action& action)
|
||||
[this, entityComponentIdPair,
|
||||
transformScale{ linearManipulator->GetSpace().GetUniformScale() }](const LinearManipulator::Action& action)
|
||||
{
|
||||
AZ::Transform boxLocalTransform = AZ::Transform::CreateIdentity();
|
||||
BoxManipulatorRequestBus::EventResult(
|
||||
boxLocalTransform, entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetCurrentLocalTransform);
|
||||
|
||||
const AZ::Vector3 manipulatorPosition = GetPositionInManipulatorFrame(transformScale, boxLocalTransform, action);
|
||||
|
||||
// calculate the amount of displacement along an axis this manipulator has moved
|
||||
// clamp movement so it cannot go negative based on axis direction
|
||||
const AZ::Vector3 axisDisplacement =
|
||||
action.LocalPosition().GetAbs() * 2.0f
|
||||
* AZ::GetMax<float>(0.0f, action.LocalPosition().GetNormalized().Dot(action.m_fixed.m_axis));
|
||||
|
||||
AZ::Vector3 boxScale = AZ::Vector3::CreateOne();
|
||||
BoxManipulatorRequestBus::EventResult(
|
||||
boxScale, entityComponentIdPair, &BoxManipulatorRequests::GetBoxScale);
|
||||
manipulatorPosition.GetAbs() * 2.0f
|
||||
* AZ::GetMax(0.0f, manipulatorPosition.GetNormalized().Dot(action.m_fixed.m_axis));
|
||||
|
||||
AZ::Vector3 boxDimensions = AZ::Vector3::CreateZero();
|
||||
BoxManipulatorRequestBus::EventResult(
|
||||
boxDimensions, entityComponentIdPair, &BoxManipulatorRequests::GetDimensions);
|
||||
|
||||
// ensure we take into account the entity scale using the axis displacement
|
||||
const AZ::Vector3 scaledAxisDisplacement =
|
||||
axisDisplacement / boxScale;
|
||||
boxDimensions, entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetDimensions);
|
||||
|
||||
// update dimensions - preserve dimensions not effected by this
|
||||
// axis, and update current axis displacement
|
||||
BoxManipulatorRequestBus::Event(
|
||||
entityComponentIdPair, &BoxManipulatorRequests::SetDimensions,
|
||||
(NotAxis(action.m_fixed.m_axis) * boxDimensions).GetMax(scaledAxisDisplacement));
|
||||
entityComponentIdPair, &BoxManipulatorRequestBus::Events::SetDimensions,
|
||||
(NotAxis(action.m_fixed.m_axis) * boxDimensions).GetMax(axisDisplacement));
|
||||
|
||||
UpdateManipulators();
|
||||
});
|
||||
@@ -137,4 +139,12 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Vector3 GetPositionInManipulatorFrame(float worldUniformScale, const AZ::Transform& manipulatorLocalTransform,
|
||||
const LinearManipulator::Action& action)
|
||||
{
|
||||
return manipulatorLocalTransform.GetInverse().TransformPoint(
|
||||
action.m_start.m_localPosition +
|
||||
action.m_current.m_localPositionOffset / AZ::GetClamp(worldUniformScale, AZ::MinTransformScale, AZ::MaxTransformScale));
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -31,4 +31,10 @@ namespace AzToolsFramework
|
||||
using BoxManipulators = AZStd::array<AZStd::shared_ptr<LinearManipulator>, 6>;
|
||||
BoxManipulators m_linearManipulators; ///< Manipulators for editing box size.
|
||||
};
|
||||
|
||||
/// Calculates the position of the manipulator in its own reference frame.
|
||||
/// Removes the effects of the manipulator local transform, and accounts for world transform scale in
|
||||
/// the action local offset.
|
||||
AZ::Vector3 GetPositionInManipulatorFrame(float worldUniformScale, const AZ::Transform& manipulatorLocalTransform,
|
||||
const LinearManipulator::Action& action);
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -54,7 +54,8 @@ namespace AzToolsFramework
|
||||
|
||||
virtual ~BaseManipulator();
|
||||
|
||||
using EntityComponentIds = AZStd::unordered_set<AZ::EntityComponentIdPair>;
|
||||
using UniqueEntityIds = AZStd::unordered_set<AZ::EntityId>;
|
||||
using UniqueEntityComponentIds = AZStd::unordered_set<AZ::EntityComponentIdPair>;
|
||||
|
||||
//! Callback for the event when the mouse pointer is over this manipulator and the left mouse button is pressed.
|
||||
//! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera
|
||||
@@ -137,7 +138,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
//! Returns all EntityComponentIdPairs associated with this manipulator.
|
||||
const EntityComponentIds& EntityComponentIdPairs() const
|
||||
const UniqueEntityComponentIds& EntityComponentIdPairs() const
|
||||
{
|
||||
return m_entityComponentIdPairs;
|
||||
}
|
||||
@@ -147,10 +148,10 @@ namespace AzToolsFramework
|
||||
|
||||
//! Remove an entity from being affected by this manipulator.
|
||||
//! @note All components on this entity registered with the manipulator will be removed.
|
||||
EntityComponentIds::iterator RemoveEntityId(AZ::EntityId entityId);
|
||||
UniqueEntityComponentIds::iterator RemoveEntityId(AZ::EntityId entityId);
|
||||
|
||||
//! Remove a specific component (via a EntityComponentIdPair) being affected by this manipulator.
|
||||
EntityComponentIds::iterator RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair);
|
||||
UniqueEntityComponentIds::iterator RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair);
|
||||
|
||||
//! Is this entity currently being tracked by this manipulator.
|
||||
bool HasEntityId(AZ::EntityId entityId) const;
|
||||
|
||||
+10
@@ -26,11 +26,21 @@ namespace AzToolsFramework
|
||||
virtual AZ::Vector3 GetDimensions() = 0;
|
||||
//! Set the X/Y/Z dimensions of the box shape/collider.
|
||||
virtual void SetDimensions(const AZ::Vector3& dimensions) = 0;
|
||||
// O3DE_DEPRECATION_NOTICE(GHI-7572)
|
||||
//! @deprecated Because non-uniform scale effects can be complex, it is recommended to separately use
|
||||
//! AZ::TransformBus::Events::GetWorldTM, AZ::NonUniformScaleRequests::GetScale and GetCurrentLocalTransform
|
||||
//! and combine their effects.
|
||||
//! Get the transform of the box shape/collider.
|
||||
//! This is used by \ref BoxComponentMode instead of the \ref \AZ::TransformBus
|
||||
//! because a collider may have an additional translation/orientation offset from
|
||||
//! the Entity transform.
|
||||
virtual AZ::Transform GetCurrentTransform() = 0;
|
||||
//! Get the transform of the box relative to the entity.
|
||||
virtual AZ::Transform GetCurrentLocalTransform() = 0;
|
||||
// O3DE_DEPRECATION_NOTICE(GHI-7572)
|
||||
//! @deprecated Because non-uniform scale effects can be complex, it is recommended to separately use
|
||||
//! AZ::TransformBus::Events::GetWorldTM, AZ::NonUniformScaleRequests::GetScale and GetCurrentLocalTransform
|
||||
//! and combine their effects.
|
||||
//! Get the scale currently applied to the box.
|
||||
//! With the Box Shape, the largest x/y/z component is taken
|
||||
//! so scale is always uniform, with colliders the scale may
|
||||
|
||||
+10
-13
@@ -80,23 +80,18 @@ namespace AzToolsFramework
|
||||
m_onMouseMoveCallback = onMouseMoveCallback;
|
||||
}
|
||||
|
||||
void SurfaceManipulator::InstallEntityIdsToIgnoreFn(EntityIdsToIgnoreFn entityIdsToIgnoreCallback)
|
||||
{
|
||||
m_entityIdsToIgnoreFn = AZStd::move(entityIdsToIgnoreCallback);
|
||||
}
|
||||
|
||||
void SurfaceManipulator::OnLeftMouseDownImpl(
|
||||
const ViewportInteraction::MouseInteraction& interaction, [[maybe_unused]] float rayIntersectionDistance)
|
||||
{
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
|
||||
|
||||
const AzFramework::ViewportId viewportId = interaction.m_interactionId.m_viewportId;
|
||||
|
||||
const auto& entityComponentIdPairs = EntityComponentIdPairs();
|
||||
m_rayRequest.m_entityFilter.m_ignoreEntities.clear();
|
||||
m_rayRequest.m_entityFilter.m_ignoreEntities.reserve(entityComponentIdPairs.size());
|
||||
AZStd::transform(
|
||||
entityComponentIdPairs.begin(), entityComponentIdPairs.end(),
|
||||
AZStd::inserter(m_rayRequest.m_entityFilter.m_ignoreEntities, m_rayRequest.m_entityFilter.m_ignoreEntities.begin()),
|
||||
[](const AZ::EntityComponentIdPair& entityComponentIdPair)
|
||||
{
|
||||
return entityComponentIdPair.GetEntityId();
|
||||
});
|
||||
m_rayRequest.m_entityFilter.m_ignoreEntities = m_entityIdsToIgnoreFn(interaction);
|
||||
|
||||
// calculate the start and end of the ray
|
||||
RefreshRayRequest(
|
||||
@@ -139,6 +134,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
const AzFramework::ViewportId viewportId = interaction.m_interactionId.m_viewportId;
|
||||
|
||||
m_rayRequest.m_entityFilter.m_ignoreEntities = m_entityIdsToIgnoreFn(interaction);
|
||||
|
||||
// update the start and end of the ray
|
||||
RefreshRayRequest(
|
||||
m_rayRequest, ViewportInteraction::ViewportScreenToWorldRay(viewportId, interaction.m_mousePick.m_screenCoordinates),
|
||||
@@ -162,12 +159,12 @@ namespace AzToolsFramework
|
||||
const ManipulatorManagerState& managerState,
|
||||
AzFramework::DebugDisplayRequests& debugDisplay,
|
||||
const AzFramework::CameraState& cameraState,
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction)
|
||||
const ViewportInteraction::MouseInteraction& interaction)
|
||||
{
|
||||
m_manipulatorView->Draw(
|
||||
GetManipulatorManagerId(), managerState, GetManipulatorId(),
|
||||
ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay,
|
||||
cameraState, mouseInteraction);
|
||||
cameraState, interaction);
|
||||
}
|
||||
|
||||
void SurfaceManipulator::InvalidateImpl()
|
||||
|
||||
@@ -40,6 +40,9 @@ namespace AzToolsFramework
|
||||
//! A Manipulator must only be created and managed through a shared_ptr.
|
||||
static AZStd::shared_ptr<SurfaceManipulator> MakeShared(const AZ::Transform& worldFromLocal);
|
||||
|
||||
//! Callback function to determine which EntityIds to ignore when performing the ray intersection.
|
||||
using EntityIdsToIgnoreFn = AZStd::function<UniqueEntityIds(const ViewportInteraction::MouseInteraction&)>;
|
||||
|
||||
//! The state of the manipulator at the start of an interaction.
|
||||
struct Start
|
||||
{
|
||||
@@ -77,11 +80,13 @@ namespace AzToolsFramework
|
||||
void InstallLeftMouseUpCallback(const MouseActionCallback& onMouseUpCallback);
|
||||
void InstallMouseMoveCallback(const MouseActionCallback& onMouseMoveCallback);
|
||||
|
||||
void InstallEntityIdsToIgnoreFn(EntityIdsToIgnoreFn entityIdsToIgnoreFn);
|
||||
|
||||
void Draw(
|
||||
const ManipulatorManagerState& managerState,
|
||||
AzFramework::DebugDisplayRequests& debugDisplay,
|
||||
const AzFramework::CameraState& cameraState,
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
|
||||
const ViewportInteraction::MouseInteraction& interaction) override;
|
||||
|
||||
void SetView(AZStd::unique_ptr<ManipulatorView>&& view);
|
||||
|
||||
@@ -109,6 +114,9 @@ namespace AzToolsFramework
|
||||
MouseActionCallback m_onLeftMouseUpCallback = nullptr;
|
||||
MouseActionCallback m_onMouseMoveCallback = nullptr;
|
||||
|
||||
//! Customization point to determine which (if any) EntityIds to ignore while performing the ray intersection.
|
||||
EntityIdsToIgnoreFn m_entityIdsToIgnoreFn = nullptr;
|
||||
|
||||
//! Cached ray request initialized at mouse down and updated during mouse move.
|
||||
AzFramework::RenderGeometry::RayRequest m_rayRequest;
|
||||
|
||||
|
||||
+9
@@ -145,6 +145,15 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void TranslationManipulators::InstallSurfaceManipulatorEntityIdsToIgnoreFn(
|
||||
SurfaceManipulator::EntityIdsToIgnoreFn entityIdsToIgnoreFn)
|
||||
{
|
||||
if (m_surfaceManipulator)
|
||||
{
|
||||
m_surfaceManipulator->InstallEntityIdsToIgnoreFn(AZStd::move(entityIdsToIgnoreFn));
|
||||
}
|
||||
}
|
||||
|
||||
void TranslationManipulators::SetLocalTransformImpl(const AZ::Transform& localTransform)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_linearManipulators)
|
||||
|
||||
+2
@@ -61,6 +61,8 @@ namespace AzToolsFramework
|
||||
void InstallSurfaceManipulatorMouseMoveCallback(const SurfaceManipulator::MouseActionCallback& onMouseMoveCallback);
|
||||
void InstallSurfaceManipulatorMouseUpCallback(const SurfaceManipulator::MouseActionCallback& onMouseUpCallback);
|
||||
|
||||
void InstallSurfaceManipulatorEntityIdsToIgnoreFn(SurfaceManipulator::EntityIdsToIgnoreFn entityIdsToIgnoreFn);
|
||||
|
||||
void SetSpaceImpl(const AZ::Transform& worldFromLocal) override;
|
||||
void SetLocalTransformImpl(const AZ::Transform& localTransform) override;
|
||||
void SetLocalPositionImpl(const AZ::Vector3& localPosition) override;
|
||||
|
||||
@@ -23,7 +23,15 @@ namespace AzToolsFramework
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ThumbnailKey
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool ThumbnailKey::IsReady() const { return m_ready; }
|
||||
void ThumbnailKey::SetReady(bool ready)
|
||||
{
|
||||
m_ready = ready;
|
||||
}
|
||||
|
||||
bool ThumbnailKey::IsReady() const
|
||||
{
|
||||
return m_ready;
|
||||
}
|
||||
|
||||
bool ThumbnailKey::UpdateThumbnail()
|
||||
{
|
||||
@@ -75,10 +83,8 @@ namespace AzToolsFramework
|
||||
if (m_state == State::Unloaded)
|
||||
{
|
||||
m_state = State::Loading;
|
||||
QThreadPool* threadPool;
|
||||
ThumbnailContextRequestBus::BroadcastResult(
|
||||
threadPool,
|
||||
&ThumbnailContextRequestBus::Handler::GetThreadPool);
|
||||
QThreadPool* threadPool = {};
|
||||
ThumbnailerRequestBus::BroadcastResult(threadPool, &ThumbnailerRequestBus::Handler::GetThreadPool);
|
||||
QFuture<void> future = QtConcurrent::run(threadPool, [this](){ LoadThread(); });
|
||||
m_watcher.setFuture(future);
|
||||
}
|
||||
|
||||
@@ -26,13 +26,11 @@ namespace AzToolsFramework
|
||||
//! ThumbnailKey is used to locate thumbnails in thumbnail cache
|
||||
/*
|
||||
ThumbnailKey contains any kind of identifiable information to retrieve thumbnails (e.g. assetId, assetType, filename, etc.)
|
||||
To use thumbnail system, keep reference to your thumbnail key, and retrieve Thumbnail via ThumbnailerRequestsBus
|
||||
To use thumbnail system, keep reference to your thumbnail key, and retrieve Thumbnail via ThumbnailerRequestBus
|
||||
*/
|
||||
class ThumbnailKey
|
||||
: public QObject
|
||||
{
|
||||
friend class ThumbnailContext;
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
AZ_RTTI(ThumbnailKey, "{43F20F6B-333D-4226-8E4F-331A62315255}");
|
||||
@@ -40,6 +38,8 @@ namespace AzToolsFramework
|
||||
ThumbnailKey() = default;
|
||||
virtual ~ThumbnailKey() = default;
|
||||
|
||||
void SetReady(bool ready);
|
||||
|
||||
bool IsReady() const;
|
||||
|
||||
virtual bool UpdateThumbnail();
|
||||
@@ -47,13 +47,13 @@ namespace AzToolsFramework
|
||||
virtual size_t GetHash() const;
|
||||
|
||||
virtual bool Equals(const ThumbnailKey* other) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
//! Updated signal is dispatched whenever thumbnail data was changed. Anyone using this thumbnail should listen to this.
|
||||
void ThumbnailUpdatedSignal() const;
|
||||
//! Force update mapped thumbnails
|
||||
void UpdateThumbnailSignal() const;
|
||||
|
||||
|
||||
private:
|
||||
bool m_ready = false;
|
||||
};
|
||||
@@ -114,11 +114,14 @@ namespace AzToolsFramework
|
||||
ThumbnailProvider() = default;
|
||||
virtual ~ThumbnailProvider() = default;
|
||||
virtual bool GetThumbnail(SharedThumbnailKey key, SharedThumbnail& thumbnail) = 0;
|
||||
//! Priority identifies ThumbnailProvider order in ThumbnailContext
|
||||
//! Higher priority means this ThumbnailProvider will take precedence in generating a thumbnail when
|
||||
//! a supplied ThumbnailKey is supported by multiple providers.
|
||||
virtual int GetPriority() const { return 0; }
|
||||
//! A unique ThumbnailProvider name identifying it in a ThumbnailContext
|
||||
//! Priority identifies ThumbnailProvider order
|
||||
//! Higher priority means this ThumbnailProvider will take precedence in generating a thumbnail when a supplied ThumbnailKey is
|
||||
//! supported by multiple providers.
|
||||
virtual int GetPriority() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
//! A unique ThumbnailProvider name identifyier
|
||||
virtual const char* GetProviderName() const = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/Thumbnails/MissingThumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/LoadingThumbnail.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4244 4251, "-Wunknown-warning-option") // 4251: 'QImageIOHandler::d_ptr': class 'QScopedPointer<QImageIOHandlerPrivate,QScopedPointerDeleter<T>>' needs to have dll-interface to be used by clients of class 'QImageIOHandler'
|
||||
#include <AzQtComponents/Components/StyledBusyLabel.h>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
ThumbnailContext::ThumbnailContext()
|
||||
: m_missingThumbnail(new MissingThumbnail())
|
||||
, m_loadingThumbnail(new LoadingThumbnail())
|
||||
, m_threadPool(this)
|
||||
{
|
||||
ThumbnailContextRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
ThumbnailContext::~ThumbnailContext()
|
||||
{
|
||||
ThumbnailContextRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
bool ThumbnailContext::IsLoading(SharedThumbnailKey key)
|
||||
{
|
||||
SharedThumbnail thumbnail;
|
||||
|
||||
for (auto& provider : m_providers)
|
||||
{
|
||||
if (provider->GetThumbnail(key, thumbnail))
|
||||
{
|
||||
return thumbnail->GetState() == Thumbnail::State::Unloaded ||
|
||||
thumbnail->GetState() == Thumbnail::State::Loading;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ThumbnailContext::RedrawThumbnail()
|
||||
{
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Broadcast(&AzToolsFramework::AssetBrowser::AssetBrowserViewRequests::Update);
|
||||
}
|
||||
|
||||
QThreadPool* ThumbnailContext::GetThreadPool()
|
||||
{
|
||||
return &m_threadPool;
|
||||
}
|
||||
|
||||
SharedThumbnail ThumbnailContext::GetThumbnail(SharedThumbnailKey key)
|
||||
{
|
||||
SharedThumbnail thumbnail;
|
||||
// find provider who can handle supplied key
|
||||
for (auto& provider : m_providers)
|
||||
{
|
||||
if (provider->GetThumbnail(key, thumbnail))
|
||||
{
|
||||
// if thumbnail is ready return it
|
||||
if (thumbnail->GetState() == Thumbnail::State::Ready)
|
||||
{
|
||||
return thumbnail;
|
||||
}
|
||||
// if thumbnail is not loaded, start loading it, meanwhile return loading thumbnail
|
||||
if (thumbnail->GetState() == Thumbnail::State::Unloaded)
|
||||
{
|
||||
// listen to the loading signal, so the anyone using it will update loading animation
|
||||
connect(m_loadingThumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
AzQtComponents::StyledBusyLabel* busyLabel;
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserComponentRequestBus::BroadcastResult(busyLabel, &AzToolsFramework::AssetBrowser::AssetBrowserComponentRequests::GetStyledBusyLabel);
|
||||
connect(busyLabel, &AzQtComponents::StyledBusyLabel::repaintNeeded, this, &ThumbnailContext::RedrawThumbnail);
|
||||
// once the thumbnail is loaded, disconnect it from loading thumbnail
|
||||
connect(thumbnail.data(), &Thumbnail::Updated, this , [this, key, thumbnail, busyLabel]()
|
||||
{
|
||||
disconnect(m_loadingThumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
disconnect(busyLabel, &AzQtComponents::StyledBusyLabel::repaintNeeded, this, &ThumbnailContext::RedrawThumbnail);
|
||||
thumbnail->disconnect();
|
||||
connect(thumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
connect(key.data(), &ThumbnailKey::UpdateThumbnailSignal, thumbnail.data(), &Thumbnail::Update);
|
||||
key->m_ready = true;
|
||||
Q_EMIT key->ThumbnailUpdatedSignal();
|
||||
});
|
||||
thumbnail->Load();
|
||||
}
|
||||
if (thumbnail->GetState() == Thumbnail::State::Failed)
|
||||
{
|
||||
return m_missingThumbnail;
|
||||
}
|
||||
return m_loadingThumbnail;
|
||||
}
|
||||
}
|
||||
return m_missingThumbnail;
|
||||
}
|
||||
|
||||
void ThumbnailContext::RegisterThumbnailProvider(SharedThumbnailProvider providerToAdd)
|
||||
{
|
||||
auto it = AZStd::find_if(m_providers.begin(), m_providers.end(), [providerToAdd](const SharedThumbnailProvider& provider)
|
||||
{
|
||||
return AZ::StringFunc::Equal(provider->GetProviderName(), providerToAdd->GetProviderName());
|
||||
});
|
||||
|
||||
if (it != m_providers.end())
|
||||
{
|
||||
AZ_Error("ThumbnailContext", false, "Provider with name %s is already registered with context.", providerToAdd->GetProviderName());
|
||||
return;
|
||||
}
|
||||
|
||||
m_providers.insert(providerToAdd);
|
||||
}
|
||||
|
||||
void ThumbnailContext::UnregisterThumbnailProvider(const char* providerName)
|
||||
{
|
||||
auto it = AZStd::remove_if(m_providers.begin(), m_providers.end(), [providerName](const SharedThumbnailProvider& provider)
|
||||
{
|
||||
return AZ::StringFunc::Equal(provider->GetProviderName(), providerName);
|
||||
});
|
||||
m_providers.erase(it, m_providers.end());
|
||||
}
|
||||
} // namespace Thumbnailer
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
#include "Thumbnails/moc_ThumbnailContext.cpp"
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QThreadPool>
|
||||
#endif
|
||||
|
||||
class QString;
|
||||
class QPixmap;
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
class ThumbnailProvider;
|
||||
|
||||
//! ThumbnailContext provides distinct thumbnail location for specific context
|
||||
/*
|
||||
There can be any number of contexts for every unique feature that may need different types of thumbnails.
|
||||
For example 'AssetBrowser' context provides thumbnails specific to Asset Browser
|
||||
'PreviewContext' may provide thumbnails for Preview Widget
|
||||
'MaterialBrowser' may provide thumbnails for Material Browser
|
||||
etc.
|
||||
*/
|
||||
class ThumbnailContext
|
||||
: public QObject
|
||||
, public ThumbnailContextRequestBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ThumbnailContext, AZ::SystemAllocator, 0);
|
||||
|
||||
ThumbnailContext();
|
||||
~ThumbnailContext() override;
|
||||
|
||||
//! Is the thumbnail currently loading or is about to load.
|
||||
bool IsLoading(SharedThumbnailKey key);
|
||||
//! Retrieve thumbnail by key, generate one if needed
|
||||
SharedThumbnail GetThumbnail(SharedThumbnailKey key);
|
||||
//! Add new thumbnail cache
|
||||
void RegisterThumbnailProvider(SharedThumbnailProvider providerToAdd);
|
||||
//! Remove thumbnail cache by name if found
|
||||
void UnregisterThumbnailProvider(const char* providerName);
|
||||
|
||||
void RedrawThumbnail();
|
||||
|
||||
//! Default context used for most thumbnails
|
||||
static constexpr const char* DefaultContext = "Default";
|
||||
|
||||
// ThumbnailContextRequestBus::Handler interface overrides...
|
||||
QThreadPool* GetThreadPool() override;
|
||||
|
||||
private:
|
||||
struct ProviderCompare {
|
||||
bool operator() (const SharedThumbnailProvider& lhs, const SharedThumbnailProvider& rhs) const
|
||||
{
|
||||
// sorting in reverse, higher priority means the provider should be considered first
|
||||
return lhs->GetPriority() > rhs->GetPriority();
|
||||
}
|
||||
};
|
||||
|
||||
//! Collection of thumbnail caches provided by this context
|
||||
AZStd::multiset<SharedThumbnailProvider, ProviderCompare> m_providers;
|
||||
//! Default missing thumbnail used when no thumbnail for given key can be found within this context
|
||||
SharedThumbnail m_missingThumbnail;
|
||||
//! Default loading thumbnail used when thumbnail is found by is not yet generated
|
||||
SharedThumbnail m_loadingThumbnail;
|
||||
//! There is only a limited number of threads on global threadPool, because there can be many thumbnails rendering at once
|
||||
//! an individual threadPool is needed to avoid deadlocks
|
||||
QThreadPool m_threadPool;
|
||||
};
|
||||
} // namespace Thumbnailer
|
||||
} // namespace AzToolsFramework
|
||||
@@ -30,14 +30,13 @@ namespace AzToolsFramework
|
||||
{
|
||||
}
|
||||
|
||||
void ThumbnailWidget::SetThumbnailKey(SharedThumbnailKey key, const char* contextName)
|
||||
void ThumbnailWidget::SetThumbnailKey(SharedThumbnailKey key)
|
||||
{
|
||||
if (m_key)
|
||||
{
|
||||
disconnect(m_key.data(), &ThumbnailKey::ThumbnailUpdatedSignal, this, &ThumbnailWidget::KeyUpdatedSlot);
|
||||
}
|
||||
m_key = key;
|
||||
m_contextName = contextName;
|
||||
connect(m_key.data(), &ThumbnailKey::ThumbnailUpdatedSignal, this, &ThumbnailWidget::KeyUpdatedSlot);
|
||||
repaint();
|
||||
}
|
||||
@@ -65,7 +64,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
// thumbnail instance is not stored locally, but retrieved each paintEvent since thumbnail mapped to a specific key may change
|
||||
SharedThumbnail thumbnail;
|
||||
ThumbnailerRequestsBus::BroadcastResult(thumbnail, &ThumbnailerRequests::GetThumbnail, m_key, m_contextName.c_str());
|
||||
ThumbnailerRequestBus::BroadcastResult(thumbnail, &ThumbnailerRequests::GetThumbnail, m_key);
|
||||
QPainter painter(this);
|
||||
|
||||
// Scaling and centering pixmap within bounds to preserve aspect ratio
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace AzToolsFramework
|
||||
~ThumbnailWidget() override = default;
|
||||
|
||||
//! Call this to set what thumbnail widget will display
|
||||
void SetThumbnailKey(SharedThumbnailKey key, const char* contextName = "Default");
|
||||
void SetThumbnailKey(SharedThumbnailKey key);
|
||||
//! Remove current thumbnail
|
||||
void ClearThumbnail();
|
||||
|
||||
@@ -44,7 +44,6 @@ namespace AzToolsFramework
|
||||
|
||||
private:
|
||||
SharedThumbnailKey m_key;
|
||||
AZStd::string m_contextName;
|
||||
|
||||
private Q_SLOTS:
|
||||
void KeyUpdatedSlot();
|
||||
|
||||
@@ -19,48 +19,30 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
//! Interaction with thumbnail context
|
||||
class ThumbnailContextRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//! Get thread pool for drawing thumbnails
|
||||
virtual QThreadPool* GetThreadPool() = 0;
|
||||
};
|
||||
|
||||
using ThumbnailContextRequestBus = AZ::EBus<ThumbnailContextRequests>;
|
||||
|
||||
//! Interaction with thumbnailer
|
||||
class ThumbnailerRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//! Add thumbnail context
|
||||
virtual void RegisterContext(const char* contextName) = 0;
|
||||
//! Add new thumbnail provider
|
||||
virtual void RegisterThumbnailProvider(SharedThumbnailProvider provider) = 0;
|
||||
|
||||
//! Remove thumbnail context and all associated ThumbnailProviders
|
||||
virtual void UnregisterContext(const char* contextName) = 0;
|
||||
|
||||
//! Return whether a given ThumbnailContext has been registered
|
||||
virtual bool HasContext(const char* contextName) const = 0;
|
||||
|
||||
//! Add new thumbnail provider to ThumbnailContext
|
||||
virtual void RegisterThumbnailProvider(SharedThumbnailProvider provider, const char* contextName) = 0;
|
||||
|
||||
//! Remove thumbnail provider from ThumbnailContext
|
||||
virtual void UnregisterThumbnailProvider(const char* providerName, const char* contextName) = 0;
|
||||
//! Remove thumbnail provider
|
||||
virtual void UnregisterThumbnailProvider(const char* providerName) = 0;
|
||||
|
||||
//! Retrieve thumbnail by key,
|
||||
//! if no thumbnail matching found, one of ThumbnailProviders will attempt to create
|
||||
//! If no compatible providers found, MissingThumbnail will be returned
|
||||
virtual SharedThumbnail GetThumbnail(SharedThumbnailKey thumbnailKey, const char* contextName) = 0;
|
||||
virtual SharedThumbnail GetThumbnail(SharedThumbnailKey thumbnailKey) = 0;
|
||||
|
||||
//! Return whether the thumbnail is loading.
|
||||
virtual bool IsLoading(SharedThumbnailKey thumbnailKey, const char* contextName) = 0;
|
||||
virtual bool IsLoading(SharedThumbnailKey thumbnailKey) = 0;
|
||||
|
||||
//! Get thread pool for drawing thumbnails
|
||||
virtual QThreadPool* GetThreadPool() = 0;
|
||||
};
|
||||
|
||||
using ThumbnailerRequestBus = AZ::EBus<ThumbnailerRequests>;
|
||||
using ThumbnailerRequestsBus = AZ::EBus<ThumbnailerRequests>; //deprecated
|
||||
|
||||
//! Request product thumbnail to be rendered
|
||||
class ThumbnailerRendererRequests
|
||||
|
||||
+97
-38
@@ -6,11 +6,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzQtComponents/Components/StyledBusyLabel.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/LoadingThumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/MissingThumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerComponent.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QStyle>
|
||||
@@ -19,8 +22,10 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
|
||||
ThumbnailerComponent::ThumbnailerComponent()
|
||||
: m_missingThumbnail(new MissingThumbnail())
|
||||
, m_loadingThumbnail(new LoadingThumbnail())
|
||||
, m_threadPool(this)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -28,14 +33,13 @@ namespace AzToolsFramework
|
||||
|
||||
void ThumbnailerComponent::Activate()
|
||||
{
|
||||
RegisterContext(ThumbnailContext::DefaultContext);
|
||||
BusConnect();
|
||||
ThumbnailerRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::Deactivate()
|
||||
{
|
||||
BusDisconnect();
|
||||
m_thumbnails.clear();
|
||||
ThumbnailerRequestBus::Handler::BusDisconnect();
|
||||
m_providers.clear();
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::Reflect(AZ::ReflectContext* context)
|
||||
@@ -49,59 +53,114 @@ namespace AzToolsFramework
|
||||
|
||||
void ThumbnailerComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("ThumbnailerService", 0x65422b97));
|
||||
incompatible.push_back(AZ_CRC_CE("ThumbnailerService"));
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("ThumbnailerService", 0x65422b97));
|
||||
provided.push_back(AZ_CRC_CE("ThumbnailerService"));
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::RegisterContext(const char* contextName)
|
||||
void ThumbnailerComponent::RegisterThumbnailProvider(SharedThumbnailProvider provider)
|
||||
{
|
||||
AZ_Assert(m_thumbnails.find(contextName) == m_thumbnails.end(), "Context %s already registered", contextName);
|
||||
m_thumbnails[contextName] = AZStd::make_shared<ThumbnailContext>();
|
||||
auto it = AZStd::find_if(m_providers.begin(), m_providers.end(), [provider](const SharedThumbnailProvider& existingProvider)
|
||||
{
|
||||
return AZ::StringFunc::Equal(provider->GetProviderName(), existingProvider->GetProviderName());
|
||||
});
|
||||
|
||||
if (it != m_providers.end())
|
||||
{
|
||||
AZ_Error("ThumbnailerComponent", false, "Provider with name %s is already registered with context.", provider->GetProviderName());
|
||||
return;
|
||||
}
|
||||
|
||||
m_providers.insert(provider);
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::UnregisterContext(const char* contextName)
|
||||
void ThumbnailerComponent::UnregisterThumbnailProvider(const char* providerName)
|
||||
{
|
||||
AZ_Assert(m_thumbnails.find(contextName) != m_thumbnails.end(), "Context %s not registered", contextName);
|
||||
m_thumbnails.erase(contextName);
|
||||
AZStd::erase_if(
|
||||
m_providers,
|
||||
[providerName](const SharedThumbnailProvider& provider)
|
||||
{
|
||||
return AZ::StringFunc::Equal(provider->GetProviderName(), providerName);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
bool ThumbnailerComponent::HasContext(const char* contextName) const
|
||||
SharedThumbnail ThumbnailerComponent::GetThumbnail(SharedThumbnailKey key)
|
||||
{
|
||||
return m_thumbnails.find(contextName) != m_thumbnails.end();
|
||||
// find provider who can handle supplied key
|
||||
for (auto& provider : m_providers)
|
||||
{
|
||||
SharedThumbnail thumbnail;
|
||||
if (provider->GetThumbnail(key, thumbnail))
|
||||
{
|
||||
// if thumbnail is ready return it
|
||||
if (thumbnail->GetState() == Thumbnail::State::Ready)
|
||||
{
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
// if thumbnail is not loaded, start loading it, meanwhile return loading thumbnail
|
||||
if (thumbnail->GetState() == Thumbnail::State::Unloaded)
|
||||
{
|
||||
// listen to the loading signal, so the anyone using it will update loading animation
|
||||
AzQtComponents::StyledBusyLabel* busyLabel;
|
||||
AssetBrowser::AssetBrowserComponentRequestBus::BroadcastResult(busyLabel, &AssetBrowser::AssetBrowserComponentRequests::GetStyledBusyLabel);
|
||||
QObject::connect(m_loadingThumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
QObject::connect(busyLabel, &AzQtComponents::StyledBusyLabel::repaintNeeded, this, &ThumbnailerComponent::RedrawThumbnail);
|
||||
|
||||
// once the thumbnail is loaded, disconnect it from loading thumbnail
|
||||
QObject::connect(thumbnail.data(), &Thumbnail::Updated, this , [this, key, thumbnail, busyLabel]()
|
||||
{
|
||||
QObject::disconnect(m_loadingThumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
QObject::disconnect(busyLabel, &AzQtComponents::StyledBusyLabel::repaintNeeded, this, &ThumbnailerComponent::RedrawThumbnail);
|
||||
|
||||
thumbnail->disconnect();
|
||||
QObject::connect(thumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
QObject::connect(key.data(), &ThumbnailKey::UpdateThumbnailSignal, thumbnail.data(), &Thumbnail::Update);
|
||||
|
||||
key->SetReady(true);
|
||||
Q_EMIT key->ThumbnailUpdatedSignal();
|
||||
});
|
||||
|
||||
thumbnail->Load();
|
||||
}
|
||||
|
||||
if (thumbnail->GetState() == Thumbnail::State::Failed)
|
||||
{
|
||||
return m_missingThumbnail;
|
||||
}
|
||||
|
||||
return m_loadingThumbnail;
|
||||
}
|
||||
}
|
||||
return m_missingThumbnail;
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::RegisterThumbnailProvider(SharedThumbnailProvider provider, const char* contextName)
|
||||
bool ThumbnailerComponent::IsLoading(SharedThumbnailKey key)
|
||||
{
|
||||
auto it = m_thumbnails.find(contextName);
|
||||
AZ_Assert(it != m_thumbnails.end(), "Context %s not registered", contextName);
|
||||
it->second->RegisterThumbnailProvider(provider);
|
||||
for (auto& provider : m_providers)
|
||||
{
|
||||
SharedThumbnail thumbnail;
|
||||
if (provider->GetThumbnail(key, thumbnail))
|
||||
{
|
||||
return thumbnail->GetState() == Thumbnail::State::Unloaded || thumbnail->GetState() == Thumbnail::State::Loading;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::UnregisterThumbnailProvider(const char* providerName, const char* contextName)
|
||||
QThreadPool* ThumbnailerComponent::GetThreadPool()
|
||||
{
|
||||
auto it = m_thumbnails.find(contextName);
|
||||
AZ_Assert(it != m_thumbnails.end(), "Context %s not registered", contextName);
|
||||
it->second->UnregisterThumbnailProvider(providerName);
|
||||
return &m_threadPool;
|
||||
}
|
||||
|
||||
SharedThumbnail ThumbnailerComponent::GetThumbnail(SharedThumbnailKey key, const char* contextName)
|
||||
void ThumbnailerComponent::RedrawThumbnail()
|
||||
{
|
||||
auto it = m_thumbnails.find(contextName);
|
||||
AZ_Assert(it != m_thumbnails.end(), "Context %s not registered", contextName);
|
||||
return it->second->GetThumbnail(key);
|
||||
AssetBrowser::AssetBrowserViewRequestBus::Broadcast(&AssetBrowser::AssetBrowserViewRequests::Update);
|
||||
}
|
||||
|
||||
bool ThumbnailerComponent::IsLoading(SharedThumbnailKey key, const char* contextName)
|
||||
{
|
||||
auto it = m_thumbnails.find(contextName);
|
||||
AZ_Assert(it != m_thumbnails.end(), "Context %s not registered", contextName);
|
||||
return it->second->IsLoading(key);
|
||||
}
|
||||
|
||||
} // namespace Thumbnailer
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
|
||||
+41
-18
@@ -7,19 +7,29 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QThreadPool>
|
||||
#endif
|
||||
|
||||
class QString;
|
||||
class QPixmap;
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
class ThumbnailContext;
|
||||
|
||||
class ThumbnailerComponent
|
||||
: public AZ::Component
|
||||
, public ThumbnailerRequestsBus::Handler
|
||||
, public ThumbnailerRequestBus::Handler
|
||||
, public QObject
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(ThumbnailerComponent, "{80090CA5-6A3A-4554-B5FE-A6D74ECB2D84}")
|
||||
@@ -27,28 +37,41 @@ namespace AzToolsFramework
|
||||
ThumbnailerComponent();
|
||||
virtual ~ThumbnailerComponent();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component overrides...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ThumbnailerRequests
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void RegisterContext(const char* contextName) override;
|
||||
void UnregisterContext(const char* contextName) override;
|
||||
bool HasContext(const char* contextName) const override;
|
||||
void RegisterThumbnailProvider(SharedThumbnailProvider provider, const char* contextName) override;
|
||||
void UnregisterThumbnailProvider(const char* providerName, const char* contextName) override;
|
||||
SharedThumbnail GetThumbnail(SharedThumbnailKey thumbnailKey, const char* contextName) override;
|
||||
bool IsLoading(SharedThumbnailKey thumbnailKey, const char* contextName) override;
|
||||
// ThumbnailerRequestBus::Handler interface overrides...
|
||||
void RegisterThumbnailProvider(SharedThumbnailProvider provider) override;
|
||||
void UnregisterThumbnailProvider(const char* providerName) override;
|
||||
SharedThumbnail GetThumbnail(SharedThumbnailKey thumbnailKey) override;
|
||||
bool IsLoading(SharedThumbnailKey thumbnailKey) override;
|
||||
QThreadPool* GetThreadPool() override;
|
||||
|
||||
void RedrawThumbnail();
|
||||
|
||||
private:
|
||||
AZStd::unordered_map<AZStd::string, AZStd::shared_ptr<ThumbnailContext>> m_thumbnails;
|
||||
struct ProviderCompare
|
||||
{
|
||||
bool operator()(const SharedThumbnailProvider& lhs, const SharedThumbnailProvider& rhs) const
|
||||
{
|
||||
// sorting in reverse, higher priority means the provider should be considered first
|
||||
return lhs->GetPriority() > rhs->GetPriority();
|
||||
}
|
||||
};
|
||||
|
||||
//! Collection of thumbnail caches provided by this context
|
||||
AZStd::multiset<SharedThumbnailProvider, ProviderCompare> m_providers;
|
||||
//! Default missing thumbnail used when no thumbnail for given key can be found within this context
|
||||
SharedThumbnail m_missingThumbnail;
|
||||
//! Default loading thumbnail used when thumbnail is found by is not yet generated
|
||||
SharedThumbnail m_loadingThumbnail;
|
||||
//! There is only a limited number of threads on global threadPool, because there can be many thumbnails rendering at once
|
||||
//! an individual threadPool is needed to avoid deadlocks
|
||||
QThreadPool m_threadPool;
|
||||
};
|
||||
} // Thumbnailer
|
||||
} // namespace AssetBrowser
|
||||
|
||||
+9
-18
@@ -9,7 +9,6 @@
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerNullComponent.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/Thumbnails/MissingThumbnail.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -47,35 +46,27 @@ namespace AzToolsFramework
|
||||
services.push_back(AZ_CRC("ThumbnailerService", 0x65422b97));
|
||||
}
|
||||
|
||||
void ThumbnailerNullComponent::RegisterContext(const char* /*contextName*/)
|
||||
void ThumbnailerNullComponent::RegisterThumbnailProvider(AzToolsFramework::Thumbnailer::SharedThumbnailProvider /*provider*/)
|
||||
{
|
||||
}
|
||||
|
||||
void ThumbnailerNullComponent::UnregisterContext(const char* /*contextName*/)
|
||||
void ThumbnailerNullComponent::UnregisterThumbnailProvider(const char* /*providerName*/)
|
||||
{
|
||||
}
|
||||
|
||||
bool ThumbnailerNullComponent::HasContext(const char* /*contextName*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void ThumbnailerNullComponent::RegisterThumbnailProvider(AzToolsFramework::Thumbnailer::SharedThumbnailProvider /*provider*/, const char* /*contextName*/)
|
||||
{
|
||||
}
|
||||
|
||||
void ThumbnailerNullComponent::UnregisterThumbnailProvider(const char* /*providerName*/, const char* /*contextName*/)
|
||||
{
|
||||
}
|
||||
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnail ThumbnailerNullComponent::GetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey /*key*/, const char* /*contextName*/)
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnail ThumbnailerNullComponent::GetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey /*key*/)
|
||||
{
|
||||
return m_nullThumbnail;
|
||||
}
|
||||
|
||||
bool ThumbnailerNullComponent::IsLoading(AzToolsFramework::Thumbnailer::SharedThumbnailKey /*thumbnailKey*/, const char* /*contextName*/)
|
||||
bool ThumbnailerNullComponent::IsLoading(AzToolsFramework::Thumbnailer::SharedThumbnailKey /*thumbnailKey*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QThreadPool* ThumbnailerNullComponent::GetThreadPool()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace Thumbnailer
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+7
-10
@@ -19,11 +19,9 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
class ThumbnailContext;
|
||||
|
||||
class ThumbnailerNullComponent
|
||||
: public AZ::Component
|
||||
, public AzToolsFramework::Thumbnailer::ThumbnailerRequestsBus::Handler
|
||||
, public AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(ThumbnailerNullComponent, "{8009D651-3FAA-9815-B99E-AF174A3B29D4}")
|
||||
@@ -42,13 +40,12 @@ namespace AzToolsFramework
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ThumbnailerRequests
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void RegisterContext(const char* contextName) override;
|
||||
void UnregisterContext(const char* contextName) override;
|
||||
bool HasContext(const char* contextName) const override;
|
||||
void RegisterThumbnailProvider(AzToolsFramework::Thumbnailer::SharedThumbnailProvider provider, const char* contextName) override;
|
||||
void UnregisterThumbnailProvider(const char* providerName, const char* contextName) override;
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnail GetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, const char* contextName) override;
|
||||
bool IsLoading(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, const char* contextName) override;
|
||||
void RegisterThumbnailProvider(AzToolsFramework::Thumbnailer::SharedThumbnailProvider provider) override;
|
||||
void UnregisterThumbnailProvider(const char* providerName) override;
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnail GetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey) override;
|
||||
bool IsLoading(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey) override;
|
||||
QThreadPool* GetThreadPool() override;
|
||||
|
||||
private:
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnail m_nullThumbnail;
|
||||
};
|
||||
|
||||
+9
-1
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h>
|
||||
#include <AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx>
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
@@ -117,9 +118,16 @@ namespace AzToolsFramework
|
||||
{
|
||||
}
|
||||
|
||||
bool EditorEntityUiHandlerBase::OnEntityDoubleClick([[maybe_unused]] AZ::EntityId entityId) const
|
||||
bool EditorEntityUiHandlerBase::OnOutlinerItemDoubleClick([[maybe_unused]] const QModelIndex& index) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::EntityId EditorEntityUiHandlerBase::GetEntityIdFromIndex(const QModelIndex& index)
|
||||
{
|
||||
QModelIndex firstColumnIndex = index.siblingAtColumn(EntityOutlinerListModel::ColumnName);
|
||||
|
||||
return AZ::EntityId(firstColumnIndex.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+12
-8
@@ -21,7 +21,6 @@ class QTreeView;
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! Defines a handler that can customize entity UI appearance and behavior in the Entity Outliner.
|
||||
//! This class is meant to be abstract, entities do not have a handler by default.
|
||||
class EditorEntityUiHandlerBase
|
||||
{
|
||||
protected:
|
||||
@@ -33,7 +32,7 @@ namespace AzToolsFramework
|
||||
public:
|
||||
EditorEntityUiHandlerId GetHandlerId();
|
||||
|
||||
// # Entity Outliner
|
||||
// # Entity Outliner Item
|
||||
|
||||
//! Returns the item info string that is appended to the item name in the Outliner.
|
||||
virtual QString GenerateItemInfoString(AZ::EntityId entityId) const;
|
||||
@@ -41,10 +40,12 @@ namespace AzToolsFramework
|
||||
virtual QString GenerateItemTooltip(AZ::EntityId entityId) const;
|
||||
//! Returns the item icon pixmap to display in the Outliner.
|
||||
virtual QIcon GenerateItemIcon(AZ::EntityId entityId) const;
|
||||
//! Returns whether the element's lock and visibility state should be accessible in the Outliner
|
||||
virtual bool CanToggleLockVisibility(AZ::EntityId entityId) const;
|
||||
//! Returns whether the element's name should be editable
|
||||
virtual bool CanRename(AZ::EntityId entityId) const;
|
||||
//! Returns whether the element's lock and visibility state should be accessible in the Outliner
|
||||
virtual bool CanToggleLockVisibility(AZ::EntityId entityId) const;
|
||||
|
||||
// Qt-specific painting functions
|
||||
|
||||
//! Paints the background of the item in the Outliner.
|
||||
virtual void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
@@ -54,24 +55,27 @@ namespace AzToolsFramework
|
||||
//! Paints the background of the descendant branches of the item in the Outliner.
|
||||
virtual void PaintDescendantBranchBackground(QPainter* painter, const QTreeView* view, const QRect& rect,
|
||||
const QModelIndex& index, const QModelIndex& descendantIndex) const;
|
||||
|
||||
//! Paints visual elements on the foreground of the item in the Outliner.
|
||||
virtual void PaintItemForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
//! Paints visual elements on the foreground of the descendants of the item in the Outliner.
|
||||
virtual void PaintDescendantForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index,
|
||||
const QModelIndex& descendantIndex) const;
|
||||
|
||||
// Outliner-specific interactions
|
||||
|
||||
//! Triggered when the entity is clicked in the Outliner.
|
||||
//! @return True if the click has been handled and should not be propagated, false otherwise.
|
||||
virtual bool OnOutlinerItemClick(const QPoint& position, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
//! Triggered when the entity is double-clicked in the Outliner.
|
||||
//! @return True if the double-click has been handled and should not be propagated, false otherwise.
|
||||
virtual bool OnOutlinerItemDoubleClick(const QModelIndex& index) const;
|
||||
//! Triggered when an entity's children are expanded in the Outliner.
|
||||
virtual void OnOutlinerItemExpand(const QModelIndex& index) const;
|
||||
//! Triggered when an entity's children are collapsed in the Outliner.
|
||||
virtual void OnOutlinerItemCollapse(const QModelIndex& index) const;
|
||||
|
||||
//! Triggered when the entity is double clicked in the Outliner or in the Viewport.
|
||||
//! @return True if the double click has been handled and should not be propagated, false otherwise.
|
||||
virtual bool OnEntityDoubleClick(AZ::EntityId entityId) const;
|
||||
protected:
|
||||
static AZ::EntityId GetEntityIdFromIndex(const QModelIndex& index);
|
||||
|
||||
private:
|
||||
EditorEntityUiHandlerId m_handlerId = 0;
|
||||
|
||||
+7
-1
@@ -2091,8 +2091,14 @@ namespace AzToolsFramework
|
||||
customOption.state ^= QStyle::State_HasFocus;
|
||||
}
|
||||
|
||||
// Don't allow to paint on the spacing column
|
||||
if (index.column() == EntityOutlinerListModel::ColumnSpacing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the Entity UI Handler
|
||||
auto firstColumnIndex = index.siblingAtColumn(0);
|
||||
auto firstColumnIndex = index.siblingAtColumn(EntityOutlinerListModel::ColumnName);
|
||||
AZ::EntityId entityId(firstColumnIndex.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId);
|
||||
|
||||
|
||||
+1
@@ -69,6 +69,7 @@ namespace AzToolsFramework
|
||||
ColumnName, //!< Entity name
|
||||
ColumnVisibilityToggle, //!< Visibility Icons
|
||||
ColumnLockToggle, //!< Lock Icons
|
||||
ColumnSpacing, //!< Spacing to allow for drag select
|
||||
ColumnSortIndex, //!< Index of sort order
|
||||
ColumnCount //!< Total number of columns
|
||||
};
|
||||
|
||||
+217
-119
@@ -30,7 +30,6 @@ namespace AzToolsFramework
|
||||
EntityOutlinerTreeView::EntityOutlinerTreeView(QWidget* pParent)
|
||||
: AzQtComponents::StyledTreeView(pParent)
|
||||
, m_queuedMouseEvent(nullptr)
|
||||
, m_draggingUnselectedItem(false)
|
||||
{
|
||||
setUniformRowHeights(true);
|
||||
setHeaderHidden(true);
|
||||
@@ -65,22 +64,6 @@ namespace AzToolsFramework
|
||||
m_expandOnlyDelay = delay;
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::ClearQueuedMouseEvent()
|
||||
{
|
||||
if (m_queuedMouseEvent)
|
||||
{
|
||||
delete m_queuedMouseEvent;
|
||||
m_queuedMouseEvent = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::leaveEvent([[maybe_unused]] QEvent* event)
|
||||
{
|
||||
m_mousePosition = QPoint(-1, -1);
|
||||
m_currentHoveredIndex = QModelIndex();
|
||||
update();
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
|
||||
{
|
||||
AzQtComponents::StyledTreeView::dataChanged(topLeft, bottomRight, roles);
|
||||
@@ -93,7 +76,7 @@ namespace AzToolsFramework
|
||||
auto modelRow = topLeft.sibling(i, EntityOutlinerListModel::ColumnName);
|
||||
if (modelRow.isValid())
|
||||
{
|
||||
checkExpandedState(modelRow);
|
||||
CheckExpandedState(modelRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,15 +91,15 @@ namespace AzToolsFramework
|
||||
auto modelRow = model()->index(i, EntityOutlinerListModel::ColumnName, parent);
|
||||
if (modelRow.isValid())
|
||||
{
|
||||
checkExpandedState(modelRow);
|
||||
recursiveCheckExpandedStates(modelRow);
|
||||
CheckExpandedState(modelRow);
|
||||
RecursiveCheckExpandedStates(modelRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
AzQtComponents::StyledTreeView::rowsInserted(parent, start, end);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::recursiveCheckExpandedStates(const QModelIndex& current)
|
||||
void EntityOutlinerTreeView::RecursiveCheckExpandedStates(const QModelIndex& current)
|
||||
{
|
||||
const int rowCount = model()->rowCount(current);
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
@@ -124,13 +107,13 @@ namespace AzToolsFramework
|
||||
auto modelRow = model()->index(i, EntityOutlinerListModel::ColumnName, current);
|
||||
if (modelRow.isValid())
|
||||
{
|
||||
checkExpandedState(modelRow);
|
||||
recursiveCheckExpandedStates(modelRow);
|
||||
CheckExpandedState(modelRow);
|
||||
RecursiveCheckExpandedStates(modelRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::checkExpandedState(const QModelIndex& current)
|
||||
void EntityOutlinerTreeView::CheckExpandedState(const QModelIndex& current)
|
||||
{
|
||||
const bool expandState = current.data(EntityOutlinerListModel::ExpandedRole).template value<bool>();
|
||||
setExpanded(current, expandState);
|
||||
@@ -138,116 +121,102 @@ namespace AzToolsFramework
|
||||
|
||||
void EntityOutlinerTreeView::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
//postponing normal mouse pressed logic until mouse is released or dragged
|
||||
//this means selection occurs on mouse released now
|
||||
//this is to support drag/drop of non-selected items
|
||||
// Postponing normal mouse press logic until mouse is released or dragged.
|
||||
// This allows drag/drop of non-selected items.
|
||||
ClearQueuedMouseEvent();
|
||||
m_queuedMouseEvent = new QMouseEvent(*event);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
// Prevent multiple updates throughout the function for changing UIs.
|
||||
bool forceUpdate = false;
|
||||
|
||||
QModelIndex previousHoveredIndex = m_currentHoveredIndex;
|
||||
m_mousePosition = event->pos();
|
||||
|
||||
if (QModelIndex hoveredIndex = indexAt(m_mousePosition);
|
||||
m_currentHoveredIndex != hoveredIndex)
|
||||
{
|
||||
m_currentHoveredIndex = hoveredIndex;
|
||||
}
|
||||
|
||||
if (m_queuedMouseEvent)
|
||||
{
|
||||
if (!m_isDragSelectActive)
|
||||
{
|
||||
// Determine whether the mouse move should trigger a rect selection or an entity drag.
|
||||
QModelIndex clickedIndex = indexAt(m_queuedMouseEvent->pos());
|
||||
// Even though the drag started on an index, we want to trigger a drag select from the last column.
|
||||
// This is to allow drag selection to be triggered from anywhere in the hierarchy.
|
||||
if (clickedIndex.isValid() && clickedIndex.column() != EntityOutlinerListModel::ColumnSpacing)
|
||||
{
|
||||
HandleDrag();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_isDragSelectActive = true;
|
||||
forceUpdate = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectAllEntitiesInSelectionRect();
|
||||
forceUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (previousHoveredIndex != m_currentHoveredIndex)
|
||||
{
|
||||
forceUpdate = true;
|
||||
}
|
||||
|
||||
if (forceUpdate)
|
||||
{
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
if (m_queuedMouseEvent && !m_draggingUnselectedItem)
|
||||
if (m_isDragSelectActive)
|
||||
{
|
||||
// mouseMoveEvent will set the state to be DraggingState, which will make Qt ignore
|
||||
// mousePressEvent in QTreeViewPrivate::expandOrCollapseItemAtPos. So we manually
|
||||
// and temporarily set it to EditingState.
|
||||
QAbstractItemView::State stateBefore = QAbstractItemView::state();
|
||||
QAbstractItemView::setState(QAbstractItemView::State::EditingState);
|
||||
|
||||
//treat this as a mouse pressed event to process selection etc
|
||||
processQueuedMousePressedEvent(m_queuedMouseEvent);
|
||||
|
||||
QAbstractItemView::setState(stateBefore);
|
||||
SelectAllEntitiesInSelectionRect();
|
||||
update();
|
||||
}
|
||||
else if (m_queuedMouseEvent)
|
||||
{
|
||||
ProcessQueuedMousePressedEvent(m_queuedMouseEvent);
|
||||
}
|
||||
|
||||
ClearQueuedMouseEvent();
|
||||
m_draggingUnselectedItem = false;
|
||||
m_isDragSelectActive = false;
|
||||
|
||||
QTreeView::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
//cancel pending mouse press
|
||||
// Cancel pending mouse press.
|
||||
ClearQueuedMouseEvent();
|
||||
QTreeView::mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
if (m_queuedMouseEvent)
|
||||
{
|
||||
//disable selection for the pending click if the mouse moved so selection is maintained for dragging
|
||||
QAbstractItemView::SelectionMode selectionModeBefore = selectionMode();
|
||||
setSelectionMode(QAbstractItemView::NoSelection);
|
||||
|
||||
//treat this as a mouse pressed event to process everything but selection, but use the position data from the mousePress message
|
||||
processQueuedMousePressedEvent(m_queuedMouseEvent);
|
||||
|
||||
//restore selection state
|
||||
setSelectionMode(selectionModeBefore);
|
||||
}
|
||||
|
||||
m_mousePosition = event->pos();
|
||||
if (QModelIndex hoveredIndex = indexAt(m_mousePosition); m_currentHoveredIndex != indexAt(m_mousePosition))
|
||||
{
|
||||
m_currentHoveredIndex = hoveredIndex;
|
||||
update();
|
||||
}
|
||||
|
||||
//process mouse movement as normal, potentially triggering drag and drop
|
||||
QTreeView::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::focusInEvent(QFocusEvent* event)
|
||||
{
|
||||
//cancel pending mouse press
|
||||
// Cancel pending mouse press.
|
||||
ClearQueuedMouseEvent();
|
||||
QTreeView::focusInEvent(event);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::focusOutEvent(QFocusEvent* event)
|
||||
{
|
||||
//cancel pending mouse press
|
||||
// Cancel pending mouse press.
|
||||
ClearQueuedMouseEvent();
|
||||
QTreeView::focusOutEvent(event);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::startDrag(Qt::DropActions supportedActions)
|
||||
{
|
||||
QModelIndex index = indexAt(m_queuedMouseEvent->pos());
|
||||
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
|
||||
AZ::EntityId parentEntityId;
|
||||
EditorEntityInfoRequestBus::EventResult(parentEntityId, entityId, &EditorEntityInfoRequestBus::Events::GetParent);
|
||||
|
||||
// If the entity is parented to a read-only entity, cancel the drag operation.
|
||||
if (m_readOnlyEntityPublicInterface->IsReadOnly(parentEntityId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//if we are attempting to drag an unselected item then we must special case drag and drop logic
|
||||
//QAbstractItemView::startDrag only supports selected items
|
||||
if (m_queuedMouseEvent)
|
||||
{
|
||||
if (!index.isValid() || index.column() != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectionModel()->isSelected(index))
|
||||
{
|
||||
StartCustomDrag({ index }, supportedActions);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StyledTreeView::startDrag(supportedActions);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::dragMoveEvent(QDragMoveEvent* event)
|
||||
void EntityOutlinerTreeView::dragMoveEvent([[maybe_unused]] QDragMoveEvent* event)
|
||||
{
|
||||
if (m_expandOnlyDelay >= 0)
|
||||
{
|
||||
@@ -257,12 +226,139 @@ namespace AzToolsFramework
|
||||
QTreeView::dragMoveEvent(event);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::dropEvent(QDropEvent* event)
|
||||
void EntityOutlinerTreeView::dropEvent([[maybe_unused]] QDropEvent* event)
|
||||
{
|
||||
emit ItemDropped();
|
||||
QTreeView::dropEvent(event);
|
||||
|
||||
m_draggingUnselectedItem = false;
|
||||
ClearQueuedMouseEvent();
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::HandleDrag()
|
||||
{
|
||||
// Retrieve the index at the click position.
|
||||
QModelIndex indexAtClick = indexAt(m_queuedMouseEvent->pos()).siblingAtColumn(EntityOutlinerListModel::ColumnName);
|
||||
|
||||
AZ::EntityId entityId(indexAtClick.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
AZ::EntityId parentEntityId;
|
||||
EditorEntityInfoRequestBus::EventResult(parentEntityId, entityId, &EditorEntityInfoRequestBus::Events::GetParent);
|
||||
|
||||
// If the entity is parented to a read-only entity, cancel the drag operation.
|
||||
if (m_readOnlyEntityPublicInterface->IsReadOnly(parentEntityId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the index is selected, we should move the whole selection.
|
||||
if (selectionModel()->isSelected(indexAtClick))
|
||||
{
|
||||
StartCustomDrag(selectionModel()->selectedIndexes(), defaultDropAction());
|
||||
}
|
||||
else
|
||||
{
|
||||
StartCustomDrag(QModelIndexList{ indexAtClick }, defaultDropAction());
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::SelectAllEntitiesInSelectionRect()
|
||||
{
|
||||
if (!m_queuedMouseEvent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the two opposing corners of the rect.
|
||||
const QPoint point1 = (m_queuedMouseEvent->pos()); // The position the drag operation started at.
|
||||
const QPoint point2 = (m_mousePosition); // The current mouse position.
|
||||
|
||||
// Determine which point's y is the top and which is the bottom.
|
||||
const int top(AZStd::min(point1.y(), point2.y()));
|
||||
const int bottom(AZStd::max(point1.y(), point2.y()));
|
||||
// We don't really need the x values for the rect, just use the center of the viewport.
|
||||
const int middle(viewport()->rect().center().x());
|
||||
|
||||
// Find the extremes of the range of indices that are in the selection rect.
|
||||
QModelIndex topIndex = indexAt(QPoint(middle, top));
|
||||
const QModelIndex bottomIndex = indexAt(QPoint(middle, bottom));
|
||||
|
||||
// If we have no top index, the mouse may have been dragged above the top item. Let's try to course correct.
|
||||
const int topDistanceForFirstItem = 10; // A reasonable distance from the top we're sure to encounter the first item.
|
||||
const QModelIndex firstIndex = indexAt(QPoint(middle, topDistanceForFirstItem));
|
||||
|
||||
if (!topIndex.isValid() && top < topDistanceForFirstItem)
|
||||
{
|
||||
topIndex = firstIndex;
|
||||
}
|
||||
|
||||
// We can assume that if topIndex is still invalid, it was below the last item in the hierarchy, hence no selection is made.
|
||||
if (!topIndex.isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QItemSelection selection;
|
||||
|
||||
// Starting from the top index, traverse all visible elements of the list and select them until the bottom index is hit.
|
||||
// If the bottom index is undefined, just keep going to the end.
|
||||
QModelIndex iter = topIndex;
|
||||
selection.select(iter, iter);
|
||||
|
||||
while (iter.isValid() && iter != bottomIndex)
|
||||
{
|
||||
iter = indexBelow(iter);
|
||||
selection.select(iter, iter);
|
||||
}
|
||||
|
||||
selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::ClearQueuedMouseEvent()
|
||||
{
|
||||
if (m_queuedMouseEvent)
|
||||
{
|
||||
delete m_queuedMouseEvent;
|
||||
m_queuedMouseEvent = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::leaveEvent([[maybe_unused]] QEvent* event)
|
||||
{
|
||||
ClearQueuedMouseEvent();
|
||||
|
||||
// Only clear the mouse position if the last mouse position registered is inside.
|
||||
// This allows drag to select to work correctly in all situations.
|
||||
if(this->viewport()->rect().contains(m_mousePosition))
|
||||
{
|
||||
m_mousePosition = QPoint(-1, -1);
|
||||
}
|
||||
m_currentHoveredIndex = QModelIndex();
|
||||
update();
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
AzQtComponents::StyledTreeView::paintEvent(event);
|
||||
|
||||
// Draw the drag selection rect.
|
||||
if (m_isDragSelectActive && m_queuedMouseEvent)
|
||||
{
|
||||
// Create a painter to draw on the viewport.
|
||||
QPainter painter(viewport());
|
||||
|
||||
// Retrieve the two corners of the rect.
|
||||
const QPoint point1 = (m_queuedMouseEvent->pos()); // The position the drag operation started at.
|
||||
const QPoint point2 = (m_mousePosition); // The current mouse position.
|
||||
|
||||
// We need the top left and bottom right corners, which may not be the two corners we got above.
|
||||
// So we composite the corners based on the coordinates of the points.
|
||||
const QPoint topLeft(AZStd::min(point1.x(), point2.x()), AZStd::min(point1.y(), point2.y()));
|
||||
const QPoint bottomRight(AZStd::max(point1.x(), point2.x()), AZStd::max(point1.y(), point2.y()));
|
||||
|
||||
// Paint the rect.
|
||||
painter.setBrush(m_dragSelectRectColor);
|
||||
painter.setPen(m_dragSelectBorderColor);
|
||||
painter.drawRect(QRect(topLeft, bottomRight));
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const
|
||||
@@ -270,7 +366,7 @@ namespace AzToolsFramework
|
||||
const bool isEnabled = (this->model()->flags(index) & Qt::ItemIsEnabled);
|
||||
|
||||
const bool isSelected = selectionModel()->isSelected(index);
|
||||
const bool isHovered = (index == indexAt(m_mousePosition).siblingAtColumn(0)) && isEnabled;
|
||||
const bool isHovered = (index == m_currentHoveredIndex.siblingAtColumn(0)) && isEnabled;
|
||||
|
||||
// Paint the branch Selection/Hover Rect
|
||||
PaintBranchSelectionHoverRect(painter, rect, isSelected, isHovered);
|
||||
@@ -352,25 +448,27 @@ namespace AzToolsFramework
|
||||
QTreeView::timerEvent(event);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::processQueuedMousePressedEvent(QMouseEvent* event)
|
||||
void EntityOutlinerTreeView::ProcessQueuedMousePressedEvent(QMouseEvent* event)
|
||||
{
|
||||
//interpret the mouse event as a button press
|
||||
QMouseEvent mousePressedEvent(
|
||||
QEvent::MouseButtonPress,
|
||||
event->localPos(),
|
||||
event->windowPos(),
|
||||
event->screenPos(),
|
||||
event->button(),
|
||||
event->buttons(),
|
||||
event->modifiers(),
|
||||
event->source());
|
||||
QTreeView::mousePressEvent(&mousePressedEvent);
|
||||
QModelIndex clickedIndex = indexAt(m_queuedMouseEvent->pos());
|
||||
if (!clickedIndex.isValid() || clickedIndex.column() != EntityOutlinerListModel::ColumnSpacing)
|
||||
{
|
||||
//interpret the mouse event as a button press
|
||||
QMouseEvent mousePressedEvent(
|
||||
QEvent::MouseButtonPress,
|
||||
event->localPos(),
|
||||
event->windowPos(),
|
||||
event->screenPos(),
|
||||
event->button(),
|
||||
event->buttons(),
|
||||
event->modifiers(),
|
||||
event->source());
|
||||
QTreeView::mousePressEvent(&mousePressedEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions)
|
||||
{
|
||||
m_draggingUnselectedItem = true;
|
||||
|
||||
//sort by container entity depth and order in hierarchy for proper drag image and drop order
|
||||
QModelIndexList indexListSorted = indexList;
|
||||
AZStd::unordered_map<AZ::EntityId, AZStd::list<AZ::u64>> locations;
|
||||
|
||||
+12
-7
@@ -63,7 +63,6 @@ namespace AzToolsFramework
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
void focusInEvent(QFocusEvent* event) override;
|
||||
void focusOutEvent(QFocusEvent* event) override;
|
||||
void startDrag(Qt::DropActions supportedActions) override;
|
||||
void dragMoveEvent(QDragMoveEvent* event) override;
|
||||
void dropEvent(QDropEvent* event) override;
|
||||
void leaveEvent(QEvent* event) override;
|
||||
@@ -71,33 +70,39 @@ namespace AzToolsFramework
|
||||
// FocusModeNotificationBus overrides ...
|
||||
void OnEditorFocusChanged(AZ::EntityId previousFocusEntityId, AZ::EntityId newFocusEntityId) override;
|
||||
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
//! Renders the left side of the item: appropriate background, branch lines, icons.
|
||||
void drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const override;
|
||||
|
||||
void timerEvent(QTimerEvent* event) override;
|
||||
private:
|
||||
void ClearQueuedMouseEvent();
|
||||
void ProcessQueuedMousePressedEvent(QMouseEvent* event);
|
||||
|
||||
void processQueuedMousePressedEvent(QMouseEvent* event);
|
||||
void recursiveCheckExpandedStates(const QModelIndex& parent);
|
||||
void checkExpandedState(const QModelIndex& current);
|
||||
void SelectAllEntitiesInSelectionRect();
|
||||
|
||||
void HandleDrag();
|
||||
void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions) override;
|
||||
|
||||
void RecursiveCheckExpandedStates(const QModelIndex& parent);
|
||||
void CheckExpandedState(const QModelIndex& current);
|
||||
|
||||
void PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const;
|
||||
void PaintBranchSelectionHoverRect(QPainter* painter, const QRect& rect, bool isSelected, bool isHovered) const;
|
||||
|
||||
QMouseEvent* m_queuedMouseEvent;
|
||||
QModelIndex m_currentHoveredIndex;
|
||||
QPoint m_mousePosition;
|
||||
bool m_draggingUnselectedItem; // This is set when an item is dragged outside its bounding box.
|
||||
|
||||
bool m_isDragSelectActive = false;
|
||||
int m_expandOnlyDelay = -1;
|
||||
QBasicTimer m_expandTimer;
|
||||
|
||||
const QColor m_selectedColor = QColor(255, 255, 255, 45);
|
||||
const QColor m_hoverColor = QColor(255, 255, 255, 30);
|
||||
|
||||
QModelIndex m_currentHoveredIndex;
|
||||
const QColor m_dragSelectRectColor = QColor(255, 255, 255, 20);
|
||||
const QColor m_dragSelectBorderColor = QColor(255, 255, 255);
|
||||
|
||||
EditorEntityUiInterface* m_editorEntityFrameworkInterface = nullptr;
|
||||
ReadOnlyEntityPublicInterface* m_readOnlyEntityPublicInterface = nullptr;
|
||||
|
||||
+4
-2
@@ -193,7 +193,6 @@ namespace AzToolsFramework
|
||||
m_listModel->SetSortMode(m_sortMode);
|
||||
|
||||
const int autoExpandDelayMilliseconds = 2500;
|
||||
m_gui->m_objectTree->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
SetDefaultTreeViewEditTriggers();
|
||||
m_gui->m_objectTree->setAutoExpandDelay(autoExpandDelayMilliseconds);
|
||||
m_gui->m_objectTree->setDragEnabled(true);
|
||||
@@ -208,6 +207,7 @@ namespace AzToolsFramework
|
||||
m_gui->m_objectTree->setAutoScrollMargin(20);
|
||||
m_gui->m_objectTree->setIndentation(24);
|
||||
m_gui->m_objectTree->setRootIsDecorated(false);
|
||||
m_gui->m_objectTree->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
connect(m_gui->m_objectTree, &QTreeView::customContextMenuRequested, this, &EntityOutlinerWidget::OnOpenTreeContextMenu);
|
||||
|
||||
// custom item delegate
|
||||
@@ -260,6 +260,8 @@ namespace AzToolsFramework
|
||||
m_gui->m_objectTree->header()->resizeSection(EntityOutlinerListModel::ColumnVisibilityToggle, 20);
|
||||
m_gui->m_objectTree->header()->setSectionResizeMode(EntityOutlinerListModel::ColumnLockToggle, QHeaderView::Fixed);
|
||||
m_gui->m_objectTree->header()->resizeSection(EntityOutlinerListModel::ColumnLockToggle, 24);
|
||||
m_gui->m_objectTree->header()->setSectionResizeMode(EntityOutlinerListModel::ColumnSpacing, QHeaderView::Fixed);
|
||||
m_gui->m_objectTree->header()->resizeSection(EntityOutlinerListModel::ColumnSpacing, 16);
|
||||
|
||||
connect(m_gui->m_objectTree->selectionModel(),
|
||||
&QItemSelectionModel::selectionChanged,
|
||||
@@ -945,7 +947,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (AZ::EntityId entityId = GetEntityIdFromIndex(index); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId))
|
||||
{
|
||||
entityUiHandler->OnEntityDoubleClick(entityId);
|
||||
entityUiHandler->OnOutlinerItemDoubleClick(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
QIcon LevelRootUiHandler::GenerateItemIcon(AZ::EntityId /*entityId*/) const
|
||||
QIcon LevelRootUiHandler::GenerateItemIcon([[maybe_unused]] AZ::EntityId entityId) const
|
||||
{
|
||||
return QIcon(m_levelRootIconPath);
|
||||
}
|
||||
@@ -62,17 +62,18 @@ namespace AzToolsFramework
|
||||
return infoString;
|
||||
}
|
||||
|
||||
bool LevelRootUiHandler::CanToggleLockVisibility(AZ::EntityId /*entityId*/) const
|
||||
bool LevelRootUiHandler::CanToggleLockVisibility([[maybe_unused]] AZ::EntityId entityId) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LevelRootUiHandler::CanRename(AZ::EntityId /*entityId*/) const
|
||||
bool LevelRootUiHandler::CanRename([[maybe_unused]] AZ::EntityId entityId) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void LevelRootUiHandler::PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& /*index*/) const
|
||||
void LevelRootUiHandler::PaintItemBackground(
|
||||
QPainter* painter, const QStyleOptionViewItem& option, [[maybe_unused]] const QModelIndex& index) const
|
||||
{
|
||||
if (!painter)
|
||||
{
|
||||
@@ -94,8 +95,10 @@ namespace AzToolsFramework
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
bool LevelRootUiHandler::OnEntityDoubleClick(AZ::EntityId entityId) const
|
||||
bool LevelRootUiHandler::OnOutlinerItemDoubleClick(const QModelIndex& index) const
|
||||
{
|
||||
AZ::EntityId entityId = GetEntityIdFromIndex(index);
|
||||
|
||||
if (auto prefabFocusPublicInterface = AZ::Interface<Prefab::PrefabFocusPublicInterface>::Get();
|
||||
!prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace AzToolsFramework
|
||||
bool CanToggleLockVisibility(AZ::EntityId entityId) const override;
|
||||
bool CanRename(AZ::EntityId entityId) const override;
|
||||
void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
bool OnEntityDoubleClick(AZ::EntityId entityId) const override;
|
||||
bool OnOutlinerItemDoubleClick(const QModelIndex& index) const override;
|
||||
|
||||
private:
|
||||
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
AZ::EntityId entityId = GetEntityIdFromIndex(index);
|
||||
const bool isFirstColumn = index.column() == EntityOutlinerListModel::ColumnName;
|
||||
const bool isLastColumn = index.column() == EntityOutlinerListModel::ColumnLockToggle;
|
||||
QModelIndex firstColumnIndex = index.siblingAtColumn(EntityOutlinerListModel::ColumnName);
|
||||
@@ -183,7 +183,7 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
AZ::EntityId entityId = GetEntityIdFromIndex(index);
|
||||
|
||||
const QTreeView* outlinerTreeView(qobject_cast<const QTreeView*>(option.widget));
|
||||
const int ancestorLeft = outlinerTreeView->visualRect(index).left() + (m_prefabBorderThickness / 2) - 1;
|
||||
@@ -283,7 +283,7 @@ namespace AzToolsFramework
|
||||
|
||||
void PrefabUiHandler::PaintItemForeground(QPainter* painter, const QStyleOptionViewItem& option, [[maybe_unused]] const QModelIndex& index) const
|
||||
{
|
||||
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
AZ::EntityId entityId = GetEntityIdFromIndex(index);
|
||||
const QPoint offset = QPoint(-18, 3);
|
||||
QModelIndex firstColumnIndex = index.siblingAtColumn(EntityOutlinerListModel::ColumnName);
|
||||
const int iconSize = 16;
|
||||
@@ -385,7 +385,7 @@ namespace AzToolsFramework
|
||||
|
||||
bool PrefabUiHandler::OnOutlinerItemClick(const QPoint& position, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
AZ::EntityId entityId = GetEntityIdFromIndex(index);
|
||||
const QPoint offset = QPoint(-18, 3);
|
||||
|
||||
if (m_prefabFocusPublicInterface->IsOwningPrefabInFocusHierarchy(entityId))
|
||||
@@ -411,7 +411,7 @@ namespace AzToolsFramework
|
||||
|
||||
void PrefabUiHandler::OnOutlinerItemCollapse(const QModelIndex& index) const
|
||||
{
|
||||
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
AZ::EntityId entityId = GetEntityIdFromIndex(index);
|
||||
|
||||
if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
{
|
||||
@@ -420,8 +420,10 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
bool PrefabUiHandler::OnEntityDoubleClick(AZ::EntityId entityId) const
|
||||
bool PrefabUiHandler::OnOutlinerItemDoubleClick(const QModelIndex& index) const
|
||||
{
|
||||
AZ::EntityId entityId = GetEntityIdFromIndex(index);
|
||||
|
||||
if (!m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
{
|
||||
// Focus on this prefab
|
||||
|
||||
@@ -43,8 +43,8 @@ namespace AzToolsFramework
|
||||
const QModelIndex& index,
|
||||
const QModelIndex& descendantIndex) const override;
|
||||
bool OnOutlinerItemClick(const QPoint& position, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
bool OnOutlinerItemDoubleClick(const QModelIndex& index) const override;
|
||||
void OnOutlinerItemCollapse(const QModelIndex& index) const override;
|
||||
bool OnEntityDoubleClick(AZ::EntityId entityId) const override;
|
||||
|
||||
protected:
|
||||
Prefab::PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr;
|
||||
|
||||
+59
-7
@@ -52,7 +52,6 @@ AZ_POP_DISABLE_WARNING
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailWidget.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/ProductThumbnail.h>
|
||||
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
||||
@@ -102,7 +101,7 @@ namespace AzToolsFramework
|
||||
m_editButton->setAutoRaise(true);
|
||||
m_editButton->setIcon(QIcon(":/stylesheet/img/UI20/open-in-internal-app.svg"));
|
||||
m_editButton->setToolTip("Edit asset");
|
||||
m_editButton->setVisible(false);
|
||||
SetEditButtonVisible(false);
|
||||
|
||||
connect(m_editButton, &QToolButton::clicked, this, &PropertyAssetCtrl::OnEditButtonClicked);
|
||||
|
||||
@@ -813,7 +812,7 @@ namespace AzToolsFramework
|
||||
selection.SetDisplayFilter(FilterConstType(compFilter));
|
||||
}
|
||||
|
||||
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parentWidget());
|
||||
PickAssetSelectionFromDialog(selection, parentWidget());
|
||||
if (selection.IsValid())
|
||||
{
|
||||
const auto product = azrtti_cast<const ProductAssetBrowserEntry*>(selection.GetResult());
|
||||
@@ -831,6 +830,11 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::PickAssetSelectionFromDialog(AssetSelectionModel& selection, QWidget* parent)
|
||||
{
|
||||
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parent);
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::OnClearButtonClicked()
|
||||
{
|
||||
ClearAssetInternal();
|
||||
@@ -961,12 +965,16 @@ namespace AzToolsFramework
|
||||
AzFramework::StringFunc::Path::GetFileName(assetPath.c_str(), m_defaultAssetHint);
|
||||
}
|
||||
m_browseEdit->setPlaceholderText((m_defaultAssetHint + m_DefaultSuffix).c_str());
|
||||
|
||||
UpdateEditButton();
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::UpdateAssetDisplay()
|
||||
{
|
||||
UpdateThumbnail();
|
||||
|
||||
UpdateEditButton();
|
||||
|
||||
if (m_currentAssetType == AZ::Data::s_invalidAssetType)
|
||||
{
|
||||
return;
|
||||
@@ -1109,7 +1117,9 @@ namespace AzToolsFramework
|
||||
|
||||
void PropertyAssetCtrl::SetEditButtonVisible(bool visible)
|
||||
{
|
||||
m_editButton->setVisible(visible);
|
||||
m_showEditButton = visible;
|
||||
m_editButton->setVisible(m_showEditButton);
|
||||
UpdateEditButton();
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetEditButtonIcon(const QIcon& icon)
|
||||
@@ -1195,7 +1205,7 @@ namespace AzToolsFramework
|
||||
SharedThumbnailKey thumbnailKey = MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, assetID);
|
||||
if (m_showThumbnail)
|
||||
{
|
||||
m_thumbnail->SetThumbnailKey(thumbnailKey, Thumbnailer::ThumbnailContext::DefaultContext);
|
||||
m_thumbnail->SetThumbnailKey(thumbnailKey);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1205,6 +1215,15 @@ namespace AzToolsFramework
|
||||
m_thumbnail->ClearThumbnail();
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::UpdateEditButton()
|
||||
{
|
||||
// if Edit button is in use (shown), enable/disable it depending on the current asset id.
|
||||
if (m_showEditButton && m_disableEditButtonWhenNoAssetSelected)
|
||||
{
|
||||
m_editButton->setEnabled(GetCurrentAssetID().IsValid());
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetClearButtonEnabled(bool enable)
|
||||
{
|
||||
m_browseEdit->setClearButtonEnabled(enable);
|
||||
@@ -1236,6 +1255,17 @@ namespace AzToolsFramework
|
||||
return m_hideProductFilesInAssetPicker;
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetDisableEditButtonWhenNoAssetSelected(bool disableEditButtonWhenNoAssetSelected)
|
||||
{
|
||||
m_disableEditButtonWhenNoAssetSelected = disableEditButtonWhenNoAssetSelected;
|
||||
UpdateEditButton();
|
||||
}
|
||||
|
||||
bool PropertyAssetCtrl::GetDisableEditButtonWhenNoAssetSelected() const
|
||||
{
|
||||
return m_disableEditButtonWhenNoAssetSelected;
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetShowThumbnail(bool enable)
|
||||
{
|
||||
m_showThumbnail = enable;
|
||||
@@ -1349,6 +1379,12 @@ namespace AzToolsFramework
|
||||
GUI->SetEditButtonTooltip(tr(buttonTooltip.c_str()));
|
||||
}
|
||||
}
|
||||
else if (attrib == AZ_CRC_CE("DisableEditButtonWhenNoAssetSelected"))
|
||||
{
|
||||
bool disableEditButtonWhenNoAssetSelected = false;
|
||||
attrValue->Read<bool>(disableEditButtonWhenNoAssetSelected);
|
||||
GUI->SetDisableEditButtonWhenNoAssetSelected(disableEditButtonWhenNoAssetSelected);
|
||||
}
|
||||
else if (attrib == AZ::Edit::Attributes::DefaultAsset)
|
||||
{
|
||||
AZ::Data::AssetId assetId;
|
||||
@@ -1492,7 +1528,7 @@ namespace AzToolsFramework
|
||||
ConsumeAttributeInternal(GUI, attrib, attrValue, debugName);
|
||||
}
|
||||
|
||||
void AssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
|
||||
void AssetPropertyHandlerDefault::WriteGUIValuesIntoPropertyInternal(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
|
||||
{
|
||||
(void)index;
|
||||
(void)node;
|
||||
@@ -1507,7 +1543,12 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetPropertyHandlerDefault::ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node)
|
||||
void AssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
|
||||
{
|
||||
WriteGUIValuesIntoPropertyInternal(index, GUI, instance, node);
|
||||
}
|
||||
|
||||
bool AssetPropertyHandlerDefault::ReadValuesIntoGUIInternal(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node)
|
||||
{
|
||||
(void)index;
|
||||
(void)node;
|
||||
@@ -1527,6 +1568,11 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssetPropertyHandlerDefault::ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node)
|
||||
{
|
||||
return ReadValuesIntoGUIInternal(index, GUI, instance, node);
|
||||
}
|
||||
|
||||
QWidget* SimpleAssetPropertyHandlerDefault::CreateGUI(QWidget* pParent)
|
||||
{
|
||||
PropertyAssetCtrl* newCtrl = aznew PropertyAssetCtrl(pParent);
|
||||
@@ -1597,6 +1643,12 @@ namespace AzToolsFramework
|
||||
GUI->SetEditButtonTooltip(tr(buttonTooltip.c_str()));
|
||||
}
|
||||
}
|
||||
else if (attrib == AZ_CRC_CE("DisableEditButtonWhenNoAssetSelected"))
|
||||
{
|
||||
bool disableEditButtonWhenNoAssetSelected = false;
|
||||
attrValue->Read<bool>(disableEditButtonWhenNoAssetSelected);
|
||||
GUI->SetDisableEditButtonWhenNoAssetSelected(disableEditButtonWhenNoAssetSelected);
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleAssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
|
||||
|
||||
+11
@@ -159,6 +159,10 @@ namespace AzToolsFramework
|
||||
//! By default the asset picker shows both on an AZ::Asset<> property. You can hide product assets with this flag.
|
||||
bool m_hideProductFilesInAssetPicker = false;
|
||||
|
||||
//! True to disable the edit button when there is no asset currently selected.
|
||||
bool m_disableEditButtonWhenNoAssetSelected = false;
|
||||
|
||||
bool m_showEditButton = false;
|
||||
bool m_showThumbnail = false;
|
||||
bool m_showThumbnailDropDownButton = false;
|
||||
EditCallbackType* m_thumbnailCallback = nullptr;
|
||||
@@ -220,6 +224,9 @@ namespace AzToolsFramework
|
||||
void SetHideProductFilesInAssetPicker(bool hide);
|
||||
bool GetHideProductFilesInAssetPicker() const;
|
||||
|
||||
void SetDisableEditButtonWhenNoAssetSelected(bool disableEditButtonWhenNoAssetSelected);
|
||||
bool GetDisableEditButtonWhenNoAssetSelected() const;
|
||||
|
||||
// Enable and configure a thumbnail widget that displays an asset preview and dropdown arrow for a dropdown menu
|
||||
void SetShowThumbnail(bool enable);
|
||||
bool GetShowThumbnail() const;
|
||||
@@ -237,6 +244,7 @@ namespace AzToolsFramework
|
||||
void SetCurrentAssetHint(const AZStd::string& hint);
|
||||
void SetDefaultAssetID(const AZ::Data::AssetId& defaultID);
|
||||
virtual void PopupAssetPicker();
|
||||
virtual void PickAssetSelectionFromDialog(AssetSelectionModel& selection, QWidget* parent);
|
||||
void OnClearButtonClicked();
|
||||
void UpdateAssetDisplay();
|
||||
void OnLineEditFocus(bool focus);
|
||||
@@ -250,6 +258,7 @@ namespace AzToolsFramework
|
||||
|
||||
private:
|
||||
void UpdateThumbnail();
|
||||
void UpdateEditButton();
|
||||
};
|
||||
|
||||
class AssetPropertyHandlerDefault
|
||||
@@ -272,7 +281,9 @@ namespace AzToolsFramework
|
||||
virtual QWidget* CreateGUI(QWidget* pParent) override;
|
||||
static void ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName);
|
||||
void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
static void WriteGUIValuesIntoPropertyInternal(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node);
|
||||
virtual void WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node) override;
|
||||
static bool ReadValuesIntoGUIInternal(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node);
|
||||
virtual bool ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node) override;
|
||||
};
|
||||
|
||||
|
||||
+10
@@ -154,6 +154,16 @@ namespace AzToolsFramework
|
||||
(void)debugName;
|
||||
}
|
||||
|
||||
// provides an option to specify reading parent element attributes.
|
||||
// This allows parent elements to override attributes of their children if needed.
|
||||
virtual void ConsumeParentAttribute(WidgetType* widget, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
(void)widget;
|
||||
(void)attrib;
|
||||
(void)attrValue;
|
||||
(void)debugName;
|
||||
}
|
||||
|
||||
// override GetFirstInTabOrder, GetLastInTabOrder in your base class to define which widget gets focus first when pressing tab,
|
||||
// and also what widget is last.
|
||||
// for example, if your widget is a compound widget and contains, say, 5 buttons
|
||||
|
||||
+35
-10
@@ -40,7 +40,14 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
void* classInstance = parent->FirstInstance(); // pointer to the owner class so we can read member variables and functions
|
||||
auto consumeAttributes = [&](const auto& attributes, const char* name)
|
||||
|
||||
void* parentClassInstance = nullptr;
|
||||
if (InstanceDataNode* parentInstanceDataNode = parent->GetParent())
|
||||
{
|
||||
parentClassInstance = parentInstanceDataNode->FirstInstance();
|
||||
}
|
||||
|
||||
auto consumeAttributes = [this, classInstance, wid](const auto& attributes, const char* name)
|
||||
{
|
||||
for (size_t i = 0; i < attributes.size(); ++i)
|
||||
{
|
||||
@@ -50,25 +57,43 @@ namespace AzToolsFramework
|
||||
}
|
||||
};
|
||||
|
||||
auto consumeParentAttributes = [this, parentClassInstance, wid](const auto& attributes, const char* name)
|
||||
{
|
||||
if (parentClassInstance)
|
||||
{
|
||||
for (size_t i = 0; i < attributes.size(); ++i)
|
||||
{
|
||||
const auto& attrPair = attributes[i];
|
||||
PropertyAttributeReader reader(parentClassInstance, &*attrPair.second);
|
||||
ConsumeParentAttribute(wid, attrPair.first, &reader, name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const AZ::SerializeContext::ClassElement* element = dataNode->GetElementMetadata();
|
||||
if (element)
|
||||
{
|
||||
consumeAttributes(element->m_attributes, element->m_name);
|
||||
const AZ::Edit::ElementData* elementEdit = dataNode->GetElementEditMetadata();
|
||||
if (elementEdit)
|
||||
|
||||
if (const AZ::Edit::ElementData* elementEdit = dataNode->GetElementEditMetadata();
|
||||
elementEdit != nullptr)
|
||||
{
|
||||
consumeAttributes(elementEdit->m_attributes, elementEdit->m_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (dataNode->GetClassMetadata())
|
||||
{
|
||||
const AZ::Edit::ClassData* classEditData = dataNode->GetClassMetadata()->m_editData;
|
||||
if (classEditData)
|
||||
const AZ::SerializeContext::ClassElement* parentElement = parent != dataNode ?
|
||||
dataNode->GetElementMetadata() :
|
||||
nullptr;
|
||||
|
||||
if (parentElement != nullptr)
|
||||
{
|
||||
for (auto it = classEditData->m_elements.begin(); it != classEditData->m_elements.end(); ++it)
|
||||
// Reuse the current instance element name for the debug name
|
||||
consumeParentAttributes(parentElement->m_attributes, element->m_name);
|
||||
|
||||
if (const AZ::Edit::ElementData* elementEdit = parent->GetElementEditMetadata();
|
||||
elementEdit != nullptr)
|
||||
{
|
||||
consumeAttributes(it->m_attributes, it->m_name);
|
||||
consumeParentAttributes(elementEdit->m_attributes, elementEdit->m_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -66,6 +66,12 @@ namespace AzToolsFramework
|
||||
class GenericEnumPropertyComboBoxHandler
|
||||
: public GenericComboBoxHandler<ValueType>
|
||||
{
|
||||
virtual void ConsumeParentAttribute(GenericComboBoxCtrlBase* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override
|
||||
{
|
||||
// Simply re-route to ConsumeAttribute since no special logic is needed.
|
||||
ConsumeAttribute(GUI, attrib, attrValue, debugName);
|
||||
}
|
||||
|
||||
virtual void ConsumeAttribute(GenericComboBoxCtrlBase* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override
|
||||
{
|
||||
(void)debugName;
|
||||
|
||||
+3
-3
@@ -65,11 +65,11 @@ namespace AzToolsFramework
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void ThumbnailPropertyCtrl::SetThumbnailKey(Thumbnailer::SharedThumbnailKey key, const char* contextName)
|
||||
void ThumbnailPropertyCtrl::SetThumbnailKey(Thumbnailer::SharedThumbnailKey key)
|
||||
{
|
||||
m_key = key;
|
||||
m_thumbnail->SetThumbnailKey(m_key, contextName);
|
||||
m_thumbnailEnlarged->SetThumbnailKey(m_key, contextName);
|
||||
m_thumbnail->SetThumbnailKey(m_key);
|
||||
m_thumbnailEnlarged->SetThumbnailKey(m_key);
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ namespace AzToolsFramework
|
||||
explicit ThumbnailPropertyCtrl(QWidget* parent = nullptr);
|
||||
|
||||
//! Call this to set what thumbnail widget will display
|
||||
void SetThumbnailKey(Thumbnailer::SharedThumbnailKey key, const char* contextName = "Default");
|
||||
void SetThumbnailKey(Thumbnailer::SharedThumbnailKey key);
|
||||
|
||||
//! Remove current thumbnail
|
||||
void ClearThumbnail();
|
||||
|
||||
+13
@@ -1360,6 +1360,19 @@ namespace AzToolsFramework
|
||||
EndRecordManipulatorCommand();
|
||||
});
|
||||
|
||||
translationManipulators->InstallSurfaceManipulatorEntityIdsToIgnoreFn(
|
||||
[this](const ViewportInteraction::MouseInteraction& interaction)
|
||||
{
|
||||
if (interaction.m_keyboardModifiers.Ctrl())
|
||||
{
|
||||
return AZStd::unordered_set<AZ::EntityId>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_selectedEntityIds;
|
||||
}
|
||||
});
|
||||
|
||||
// transfer ownership
|
||||
m_entityIdManipulators.m_manipulators = AZStd::move(translationManipulators);
|
||||
}
|
||||
|
||||
@@ -86,8 +86,6 @@ set(FILES
|
||||
Thumbnails/Thumbnail.cpp
|
||||
Thumbnails/Thumbnail.h
|
||||
Thumbnails/Thumbnail.inl
|
||||
Thumbnails/ThumbnailContext.cpp
|
||||
Thumbnails/ThumbnailContext.h
|
||||
Thumbnails/ThumbnailerBus.h
|
||||
Thumbnails/ThumbnailWidget.cpp
|
||||
Thumbnails/ThumbnailWidget.h
|
||||
|
||||
@@ -3276,4 +3276,45 @@ namespace UnitTest
|
||||
const AZ::Transform finalEntityTransform = AzToolsFramework::GetWorldTransform(m_entityIdBox);
|
||||
EXPECT_THAT(finalEntityTransform.GetTranslation(), IsCloseTolerance(expectedWorldPosition, 0.01f));
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
EditorTransformComponentSelectionRenderGeometryIntersectionManipulatorFixture, SurfaceManipulatorSelfIntersectsMeshWhenCtrlIsHeld)
|
||||
{
|
||||
// camera (go to position format) - 47.00, -52.00, 20.00, 0.00, -60.00
|
||||
m_cameraState.m_viewportSize = AZ::Vector2(1280.0f, 720.0f);
|
||||
// position camera
|
||||
AzFramework::SetCameraTransform(
|
||||
m_cameraState,
|
||||
AZ::Transform::CreateFromMatrix3x3AndTranslation(
|
||||
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(-60.0f)), AZ::Vector3(47.0f, -52.0f, 20.0f)));
|
||||
// position box
|
||||
AzToolsFramework::SetWorldTransform(m_entityIdBox, AZ::Transform::CreateTranslation(AZ::Vector3(50.0f, -50.0f, 20.0f)));
|
||||
|
||||
// the initial starting position of the entity
|
||||
const auto initialTransformWorld = AzToolsFramework::GetWorldTransform(m_entityIdBox);
|
||||
// where the surface manipulator should end up (surface of the box)
|
||||
const auto finalTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(49.5f, -49.6337357f, 19.5793953f));
|
||||
|
||||
// calculate the position in screen space of the initial position of the entity
|
||||
const auto initialPositionScreen = AzFramework::WorldToScreen(initialTransformWorld.GetTranslation(), m_cameraState);
|
||||
// calculate the position in screen space of the final position of the entity
|
||||
const auto finalPositionScreen = AzFramework::WorldToScreen(finalTransformWorld.GetTranslation(), m_cameraState);
|
||||
|
||||
// select the entity (this will cause the manipulators to appear in EditorTransformComponentSelection)
|
||||
AzToolsFramework::SelectEntity(m_entityIdBox);
|
||||
|
||||
// press and drag the mouse (starting where the surface manipulator is)
|
||||
m_actionDispatcher->CameraState(m_cameraState)
|
||||
->MousePosition(initialPositionScreen)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(finalPositionScreen)
|
||||
->MouseLButtonUp();
|
||||
|
||||
// read back the position of the entity now
|
||||
const AZ::Transform finalManipulatorTransform = GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity());
|
||||
|
||||
// ensure final world positions match
|
||||
EXPECT_THAT(finalManipulatorTransform, IsCloseTolerance(finalTransformWorld, 0.01f));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace UnitTest
|
||||
// When no containers are in the way, the function will just return the entityId of the entity that was clicked.
|
||||
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
ClickAtWorldPositionOnViewport(s_worldCarEntityPosition);
|
||||
|
||||
// Verify the correct entity is selected
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
@@ -29,7 +29,7 @@ namespace UnitTest
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); // Containers are closed by default
|
||||
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
ClickAtWorldPositionOnViewport(s_worldCarEntityPosition);
|
||||
|
||||
// Verify the correct entity is selected
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
@@ -47,7 +47,7 @@ namespace UnitTest
|
||||
m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true);
|
||||
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
ClickAtWorldPositionOnViewport(s_worldCarEntityPosition);
|
||||
|
||||
// Verify the correct entity is selected
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
@@ -65,7 +65,7 @@ namespace UnitTest
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]);
|
||||
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
ClickAtWorldPositionOnViewport(s_worldCarEntityPosition);
|
||||
|
||||
// Verify the correct entity is selected
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
@@ -85,7 +85,7 @@ namespace UnitTest
|
||||
m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], true);
|
||||
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
ClickAtWorldPositionOnViewport(s_worldCarEntityPosition);
|
||||
|
||||
// Verify the correct entity is selected
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <Tests/FocusMode/EditorFocusModeFixture.h>
|
||||
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
|
||||
#include <Tests/BoundsTestComponent.h>
|
||||
@@ -93,10 +94,13 @@ namespace UnitTest
|
||||
entity->CreateComponent<UnitTest::BoundsTestComponent>();
|
||||
entity->Activate();
|
||||
|
||||
// Move the CarEntity so it's out of the way.
|
||||
AZ::TransformBus::Event(m_entityMap[CarEntityName], &AZ::TransformBus::Events::SetWorldTranslation, WorldCarEntityPosition);
|
||||
// Move the City so that it is in view
|
||||
AZ::TransformBus::Event(m_entityMap[CityEntityName], &AZ::TransformBus::Events::SetWorldTranslation, s_worldCityEntityPosition);
|
||||
|
||||
// Setup the camera so the Car entity is in view.
|
||||
// Move the CarEntity so that it's not overlapping with the rest
|
||||
AZ::TransformBus::Event(m_entityMap[CarEntityName], &AZ::TransformBus::Events::SetWorldTranslation, s_worldCarEntityPosition);
|
||||
|
||||
// Setup the camera so the entities is in view.
|
||||
AzFramework::SetCameraTransform(
|
||||
m_cameraState,
|
||||
AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
@@ -113,4 +117,5 @@ namespace UnitTest
|
||||
|
||||
return entity->GetId();
|
||||
}
|
||||
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
|
||||
@@ -38,9 +37,6 @@ namespace UnitTest
|
||||
AzToolsFramework::EntityIdList GetSelectedEntities();
|
||||
|
||||
AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
AzFramework::CameraState m_cameraState;
|
||||
|
||||
inline static const AZ::Vector3 CameraPosition = AZ::Vector3(10.0f, 15.0f, 10.0f);
|
||||
|
||||
inline static const char* CityEntityName = "City";
|
||||
inline static const char* StreetEntityName = "Street";
|
||||
@@ -49,7 +45,11 @@ namespace UnitTest
|
||||
inline static const char* Passenger1EntityName = "Passenger1";
|
||||
inline static const char* Passenger2EntityName = "Passenger2";
|
||||
|
||||
inline static AZ::Vector3 WorldCarEntityPosition = AZ::Vector3(5.0f, 15.0f, 0.0f);
|
||||
AzFramework::CameraState m_cameraState;
|
||||
|
||||
inline static const AZ::Vector3 CameraPosition = AZ::Vector3(10.0f, 15.0f, 10.0f);
|
||||
inline static AZ::Vector3 s_worldCityEntityPosition = AZ::Vector3(5.0f, 10.0f, 0.0f);
|
||||
inline static AZ::Vector3 s_worldCarEntityPosition = AZ::Vector3(5.0f, 15.0f, 0.0f);
|
||||
};
|
||||
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -45,5 +45,20 @@ namespace UnitTest
|
||||
// Click the entity in the viewport
|
||||
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(carScreenPosition)->MouseLButtonDown()->MouseLButtonUp();
|
||||
}
|
||||
|
||||
void BoxSelectOnViewport()
|
||||
{
|
||||
// Calculate the position in screen space of where to begin and end the box select action
|
||||
const auto beginningPositionWorldBoxSelect = AzFramework::WorldToScreen(AZ::Vector3(-10.0f, 15.0f, 5.0f), m_cameraState);
|
||||
const auto endingPositionWorldBoxSelect = AzFramework::WorldToScreen(AZ::Vector3(10.0f, 15.0f, -5.0f), m_cameraState);
|
||||
|
||||
// Perform a box select in the viewport
|
||||
m_actionDispatcher->SetStickySelect(true)
|
||||
->CameraState(m_cameraState)
|
||||
->MousePosition(beginningPositionWorldBoxSelect)
|
||||
->MouseLButtonDown()
|
||||
->MousePosition(endingPositionWorldBoxSelect)
|
||||
->MouseLButtonUp();
|
||||
}
|
||||
};
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace UnitTest
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnLevel)
|
||||
{
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
ClickAtWorldPositionOnViewport(s_worldCarEntityPosition);
|
||||
|
||||
// Verify entity is selected
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
@@ -27,7 +27,7 @@ namespace UnitTest
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]);
|
||||
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
ClickAtWorldPositionOnViewport(s_worldCarEntityPosition);
|
||||
|
||||
// Verify entity is selected
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
@@ -41,7 +41,7 @@ namespace UnitTest
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]);
|
||||
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
ClickAtWorldPositionOnViewport(s_worldCarEntityPosition);
|
||||
|
||||
// Verify entity is selected
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
@@ -55,7 +55,7 @@ namespace UnitTest
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[SportsCarEntityName]);
|
||||
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
ClickAtWorldPositionOnViewport(s_worldCarEntityPosition);
|
||||
|
||||
// Verify entity is selected
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
@@ -68,10 +68,71 @@ namespace UnitTest
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger1EntityName]);
|
||||
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
ClickAtWorldPositionOnViewport(s_worldCarEntityPosition);
|
||||
|
||||
// Verify entity is selected
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
EXPECT_EQ(selectedEntitiesAfter.size(), 0);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionBoxSelectWithFocusOnLevel)
|
||||
{
|
||||
// Do a box select that includes all entities in the fixture
|
||||
BoxSelectOnViewport();
|
||||
|
||||
// Entities are selected
|
||||
using ::testing::UnorderedElementsAre;
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
EXPECT_THAT(selectedEntitiesAfter,
|
||||
UnorderedElementsAre(
|
||||
m_entityMap[CityEntityName],
|
||||
m_entityMap[StreetEntityName],
|
||||
m_entityMap[CarEntityName],
|
||||
m_entityMap[Passenger1EntityName],
|
||||
m_entityMap[SportsCarEntityName],
|
||||
m_entityMap[Passenger2EntityName]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionBoxSelectWithFocusOnChild)
|
||||
{
|
||||
// Set the focus on the Passenger1 Entity (child of the entity)
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]);
|
||||
|
||||
// Do a box select that includes all entities in the fixture
|
||||
BoxSelectOnViewport();
|
||||
|
||||
// Entities are selected
|
||||
using ::testing::UnorderedElementsAre;
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
EXPECT_THAT(selectedEntitiesAfter,
|
||||
UnorderedElementsAre(
|
||||
m_entityMap[StreetEntityName],
|
||||
m_entityMap[CarEntityName],
|
||||
m_entityMap[Passenger1EntityName],
|
||||
m_entityMap[SportsCarEntityName],
|
||||
m_entityMap[Passenger2EntityName]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionBoxSelectWithFocusOnLeaf)
|
||||
{
|
||||
// Set the focus on the Passenger1 Entity (child of the entity)
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger1EntityName]);
|
||||
|
||||
// Do a box select that includes all entities in the fixture
|
||||
BoxSelectOnViewport();
|
||||
|
||||
// Entities are selected
|
||||
using ::testing::UnorderedElementsAre;
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
EXPECT_THAT(selectedEntitiesAfter,
|
||||
UnorderedElementsAre(
|
||||
m_entityMap[Passenger1EntityName]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -71,83 +71,4 @@ namespace UnitTest
|
||||
|
||||
AZ::Entity* m_testEntity = nullptr;
|
||||
};
|
||||
|
||||
TEST_F(ThumbnailerTests, ThumbnailerComponent_RegisterUnregisterContext)
|
||||
{
|
||||
constexpr const char* contextName1 = "Context1";
|
||||
constexpr const char* contextName2 = "Context2";
|
||||
|
||||
auto checkHasContext = [](const char* contextName)
|
||||
{
|
||||
bool hasContext = false;
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::BroadcastResult(hasContext, &AzToolsFramework::Thumbnailer::ThumbnailerRequests::HasContext, contextName);
|
||||
return hasContext;
|
||||
};
|
||||
|
||||
EXPECT_FALSE(checkHasContext(contextName1));
|
||||
EXPECT_FALSE(checkHasContext(contextName2));
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Broadcast(&AzToolsFramework::Thumbnailer::ThumbnailerRequests::RegisterContext, contextName1);
|
||||
|
||||
EXPECT_TRUE(checkHasContext(contextName1));
|
||||
EXPECT_FALSE(checkHasContext(contextName2));
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Broadcast(&AzToolsFramework::Thumbnailer::ThumbnailerRequests::RegisterContext, contextName2);
|
||||
|
||||
EXPECT_TRUE(checkHasContext(contextName1));
|
||||
EXPECT_TRUE(checkHasContext(contextName2));
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Broadcast(&AzToolsFramework::Thumbnailer::ThumbnailerRequests::UnregisterContext, contextName1);
|
||||
|
||||
EXPECT_FALSE(checkHasContext(contextName1));
|
||||
EXPECT_TRUE(checkHasContext(contextName2));
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Broadcast(&AzToolsFramework::Thumbnailer::ThumbnailerRequests::UnregisterContext, contextName2);
|
||||
|
||||
EXPECT_FALSE(checkHasContext(contextName1));
|
||||
EXPECT_FALSE(checkHasContext(contextName2));
|
||||
}
|
||||
|
||||
TEST_F(ThumbnailerTests, ThumbnailerComponent_Deactivate_ClearTumbnailContexts)
|
||||
{
|
||||
constexpr const char* contextName1 = "Context1";
|
||||
constexpr const char* contextName2 = "Context2";
|
||||
|
||||
auto checkHasContext = [](const char* contextName)
|
||||
{
|
||||
bool hasContext = false;
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::BroadcastResult(hasContext, &AzToolsFramework::Thumbnailer::ThumbnailerRequests::HasContext, contextName);
|
||||
return hasContext;
|
||||
};
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Broadcast(&AzToolsFramework::Thumbnailer::ThumbnailerRequests::RegisterContext, contextName1);
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Broadcast(&AzToolsFramework::Thumbnailer::ThumbnailerRequests::RegisterContext, contextName2);
|
||||
|
||||
EXPECT_TRUE(checkHasContext(contextName1));
|
||||
EXPECT_TRUE(checkHasContext(contextName2));
|
||||
|
||||
m_testEntity->Deactivate();
|
||||
m_testEntity->Activate();
|
||||
|
||||
EXPECT_FALSE(checkHasContext(contextName1));
|
||||
EXPECT_FALSE(checkHasContext(contextName2));
|
||||
}
|
||||
|
||||
TEST_F(ThumbnailerTests, ThumbnailerComponent_RegisterContextTwice_Assert)
|
||||
{
|
||||
constexpr const char* contextName1 = "Context1";
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Broadcast(&AzToolsFramework::Thumbnailer::ThumbnailerRequests::RegisterContext, contextName1);
|
||||
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Broadcast(&AzToolsFramework::Thumbnailer::ThumbnailerRequests::RegisterContext, contextName1);
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
}
|
||||
|
||||
TEST_F(ThumbnailerTests, ThumbnailerComponent_UnregisterUnknownContext_Assert)
|
||||
{
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Broadcast(&AzToolsFramework::Thumbnailer::ThumbnailerRequests::UnregisterContext, "ContextDoesNotExist");
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
Reference in New Issue
Block a user