Merge branch 'development' of https://github.com/o3de/o3de into daimini/FocusMode/breadcrumbs
Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> # Conflicts: # Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp
This commit is contained in:
+7
-1
@@ -138,7 +138,13 @@ namespace AzToolsFramework
|
||||
m_indexMap[row] = index;
|
||||
m_rowMap[index] = row;
|
||||
++row;
|
||||
++m_displayedItemsCounter;
|
||||
|
||||
// We only want to increase the displayed counter if it is a parent (Source)
|
||||
// so we don't cut children entries.
|
||||
if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source)
|
||||
{
|
||||
++m_displayedItemsCounter;
|
||||
}
|
||||
}
|
||||
|
||||
if (model->hasChildren(index))
|
||||
|
||||
+6
-4
@@ -29,20 +29,20 @@ namespace AzToolsFramework
|
||||
{
|
||||
AssetBrowserTableView::AssetBrowserTableView(QWidget* parent)
|
||||
: AzQtComponents::TableView(parent)
|
||||
, m_delegate(new EntryDelegate(this))
|
||||
, m_delegate(new SearchEntryDelegate(this))
|
||||
{
|
||||
setSortingEnabled(true);
|
||||
setSortingEnabled(false);
|
||||
setItemDelegate(m_delegate);
|
||||
setRootIsDecorated(false);
|
||||
|
||||
//Styling the header aligning text to the left and using a bold font.
|
||||
header()->setDefaultAlignment(Qt::AlignLeft);
|
||||
header()->setStyleSheet("QHeaderView { font-weight: bold; }");
|
||||
header()->setStyleSheet("QHeaderView { font-weight: bold; };");
|
||||
|
||||
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
setMouseTracking(true);
|
||||
setSortingEnabled(false);
|
||||
setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
connect(this, &AzQtComponents::TableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu);
|
||||
@@ -67,6 +67,8 @@ namespace AzToolsFramework
|
||||
|
||||
header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
|
||||
header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
|
||||
header()->setSortIndicatorShown(false);
|
||||
header()->setSectionsClickable(false);
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::SetName(const QString& name)
|
||||
|
||||
+4
-4
@@ -26,7 +26,7 @@ namespace AzToolsFramework
|
||||
class AssetBrowserEntry;
|
||||
class AssetBrowserTableModel;
|
||||
class AssetBrowserFilterModel;
|
||||
class EntryDelegate;
|
||||
class SearchEntryDelegate;
|
||||
|
||||
class AssetBrowserTableView //! Table view that displays the asset browser entries in a list.
|
||||
: public AzQtComponents::TableView
|
||||
@@ -67,9 +67,9 @@ namespace AzToolsFramework
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QPointer<AssetBrowserTableModel> m_tableModel = nullptr;
|
||||
QPointer<AssetBrowserFilterModel> m_sourceFilterModel = nullptr;
|
||||
EntryDelegate* m_delegate = nullptr;
|
||||
QPointer<AssetBrowserTableModel> m_tableModel;
|
||||
QPointer<AssetBrowserFilterModel> m_sourceFilterModel;
|
||||
SearchEntryDelegate* m_delegate = nullptr;
|
||||
|
||||
private Q_SLOTS:
|
||||
void OnContextMenu(const QPoint& point);
|
||||
|
||||
+167
-6
@@ -11,12 +11,13 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Views/EntryDelegate.h>
|
||||
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzQtComponents/Components/StyledBusyLabel.h>
|
||||
|
||||
#include <QApplication>
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer<QBrushData,QBrushDataPointerDeleter>' needs to have dll-interface to be used by clients of class 'QBrush'
|
||||
// 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning)
|
||||
#include <QAbstractItemView>
|
||||
#include <QPainter>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
@@ -24,8 +25,13 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
const int ENTRY_SPACING_LEFT_PIXELS = 8;
|
||||
const int ENTRY_ICON_MARGIN_LEFT_PIXELS = 2;
|
||||
static constexpr const char* TreeIconPathFirst = "Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg";
|
||||
static constexpr const char* TreeIconPathMiddle = "Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg";
|
||||
static constexpr const char* TreeIconPathLast = "Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg";
|
||||
static constexpr const char* TreeIconPathOneChild = "Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg";
|
||||
|
||||
const int EntrySpacingLeftPixels = 8;
|
||||
const int EntryIconMarginLeftPixels = 2;
|
||||
|
||||
EntryDelegate::EntryDelegate(QWidget* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
@@ -62,7 +68,7 @@ namespace AzToolsFramework
|
||||
|
||||
// Draw main entry thumbnail.
|
||||
QRect remainingRect(option.rect);
|
||||
remainingRect.adjust(ENTRY_ICON_MARGIN_LEFT_PIXELS, 0, 0, 0); // bump it rightwards to give some margin to the icon.
|
||||
remainingRect.adjust(EntryIconMarginLeftPixels, 0, 0, 0); // bump it rightwards to give some margin to the icon.
|
||||
|
||||
QSize iconSize(m_iconSize, m_iconSize);
|
||||
// Note that the thumbnail might actually be smaller than the row if theres a lot of padding or font size
|
||||
@@ -89,7 +95,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
remainingRect.adjust(thumbX, 0, 0, 0); // bump it to the right by the size of the thumbnail
|
||||
remainingRect.adjust(ENTRY_SPACING_LEFT_PIXELS, 0, 0, 0); // bump it to the right by the spacing.
|
||||
remainingRect.adjust(EntrySpacingLeftPixels, 0, 0, 0); // bump it to the right by the spacing.
|
||||
}
|
||||
QString displayString = index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name)
|
||||
? qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Name)))
|
||||
@@ -148,7 +154,162 @@ namespace AzToolsFramework
|
||||
return m_iconSize;
|
||||
}
|
||||
|
||||
} // namespace Thumbnailer
|
||||
SearchEntryDelegate::SearchEntryDelegate(QWidget* parent)
|
||||
: EntryDelegate(parent)
|
||||
{
|
||||
LoadBranchPixMaps();
|
||||
}
|
||||
|
||||
void SearchEntryDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
auto data = index.data(AssetBrowserModel::Roles::EntryRole);
|
||||
if (data.canConvert<const AssetBrowserEntry*>())
|
||||
{
|
||||
bool isEnabled = (option.state & QStyle::State_Enabled) != 0;
|
||||
bool isSelected = (option.state & QStyle::State_Selected) != 0;
|
||||
|
||||
QStyle* style = option.widget ? option.widget->style() : QApplication::style();
|
||||
|
||||
// draw the background
|
||||
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, option.widget);
|
||||
|
||||
// Draw main entry thumbnail.
|
||||
QRect remainingRect(option.rect);
|
||||
|
||||
QSize iconSize(m_iconSize, m_iconSize);
|
||||
// Note that the thumbnail might actually be smaller than the row if theres a lot of padding or font size
|
||||
// so it needs to center vertically with padding in that case:
|
||||
QPoint iconTopLeft;
|
||||
QPoint branchIconTopLeft = QPoint();
|
||||
|
||||
auto entry = qvariant_cast<const AssetBrowserEntry*>(data);
|
||||
auto sourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(entry);
|
||||
|
||||
//If it is a SourceEntry or it is not the column name we don't want to add space for the branch Icon
|
||||
if (sourceEntry || index.column() != aznumeric_cast<int>(AssetBrowserEntry::Column::Name))
|
||||
{
|
||||
remainingRect.adjust(EntryIconMarginLeftPixels, 0, 0, 0); // bump it rightwards to give some margin to the icon.
|
||||
iconTopLeft = QPoint(remainingRect.x(), remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
remainingRect.adjust(EntryIconMarginLeftPixels + m_iconSize, 0, 0, 0); // bump it rightwards to give some margin to the icon.
|
||||
iconTopLeft = QPoint(remainingRect.x() / 2 + m_iconSize, remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
|
||||
branchIconTopLeft = QPoint((remainingRect.x() / 2) - 2, remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
|
||||
}
|
||||
|
||||
QPalette actualPalette(option.palette);
|
||||
|
||||
if (index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name))
|
||||
{
|
||||
int thumbX = DrawThumbnail(painter, iconTopLeft, iconSize, entry->GetThumbnailKey());
|
||||
if (sourceEntry)
|
||||
{
|
||||
if (m_showSourceControl)
|
||||
{
|
||||
DrawThumbnail(painter, iconTopLeft, iconSize, sourceEntry->GetSourceControlThumbnailKey());
|
||||
}
|
||||
// sources with no children should be greyed out.
|
||||
if (sourceEntry->GetChildCount() == 0)
|
||||
{
|
||||
isEnabled = false; // draw in disabled style.
|
||||
actualPalette.setCurrentColorGroup(QPalette::Disabled);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Get the indexes above and below our entry to see what type are they.
|
||||
QAbstractItemView* view = qobject_cast<QAbstractItemView*>(option.styleObject);
|
||||
const QAbstractItemModel* viewModel = view->model();
|
||||
|
||||
const QModelIndex indexBelow = viewModel->index(index.row() + 1, index.column());
|
||||
const QModelIndex indexAbove = viewModel->index(index.row() - 1, index.column());
|
||||
|
||||
auto aboveEntry = qvariant_cast<const AssetBrowserEntry*>(indexBelow.data(AssetBrowserModel::Roles::EntryRole));
|
||||
auto belowEntry = qvariant_cast<const AssetBrowserEntry*>(indexAbove.data(AssetBrowserModel::Roles::EntryRole));
|
||||
|
||||
auto aboveSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(aboveEntry);
|
||||
auto belowSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(belowEntry);
|
||||
|
||||
// if current index is the last entry in the view
|
||||
// or the index above it is a Source Entry and
|
||||
// the index below is invalid or is valid but it is also a source entry
|
||||
// then the current index is the only child.
|
||||
if (index.row() == viewModel->rowCount() - 1 ||
|
||||
(indexBelow.isValid() && aboveSourceEntry &&
|
||||
(!indexAbove.isValid() || (indexAbove.isValid() && belowSourceEntry))))
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::OneChild, painter, branchIconTopLeft, iconSize); // Draw One Child Icon
|
||||
}
|
||||
else if (indexBelow.isValid() && aboveSourceEntry) // The index above is a source entry
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::Last, painter, branchIconTopLeft, iconSize); // Draw First child Icon
|
||||
}
|
||||
else if (indexAbove.isValid() && belowSourceEntry) // The index below is a source entry
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::First, painter, branchIconTopLeft, iconSize); // Draw Last Child Icon
|
||||
}
|
||||
else //the index above and below are also child entries
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::Middle, painter, branchIconTopLeft, iconSize); // Draw Default child Icon.
|
||||
}
|
||||
}
|
||||
|
||||
remainingRect.adjust(thumbX, 0, 0, 0); // bump it to the right by the size of the thumbnail
|
||||
remainingRect.adjust(EntrySpacingLeftPixels, 0, 0, 0); // bump it to the right by the spacing.
|
||||
}
|
||||
QString displayString = index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name)
|
||||
? qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Name)))
|
||||
: qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Path)));
|
||||
|
||||
style->drawItemText(
|
||||
painter, remainingRect, option.displayAlignment, actualPalette, isEnabled, displayString,
|
||||
isSelected ? QPalette::HighlightedText : QPalette::Text);
|
||||
}
|
||||
}
|
||||
|
||||
void SearchEntryDelegate::LoadBranchPixMaps()
|
||||
{
|
||||
AZ::IO::BasicPath<AZ::IO::FixedMaxPathString> absoluteIconPath;
|
||||
for (int branchType = EntryBranchType::First; branchType != EntryBranchType::Count; ++branchType)
|
||||
{
|
||||
QPixmap pixmap;
|
||||
switch (branchType)
|
||||
{
|
||||
case AzToolsFramework::AssetBrowser::EntryBranchType::First:
|
||||
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathFirst;
|
||||
break;
|
||||
case AzToolsFramework::AssetBrowser::EntryBranchType::Middle:
|
||||
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathMiddle;
|
||||
break;
|
||||
case AzToolsFramework::AssetBrowser::EntryBranchType::Last:
|
||||
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathLast;
|
||||
break;
|
||||
case AzToolsFramework::AssetBrowser::EntryBranchType::OneChild:
|
||||
default:
|
||||
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathOneChild;
|
||||
break;
|
||||
}
|
||||
bool pixmapLoadedSuccess = pixmap.load(absoluteIconPath.c_str());
|
||||
AZ_Assert(pixmapLoadedSuccess, "Error loading Branch Icons in SearchEntryDelegate");
|
||||
|
||||
m_branchIcons[static_cast<EntryBranchType>(branchType)] = pixmap;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SearchEntryDelegate::DrawBranchPixMap(
|
||||
EntryBranchType branchType, QPainter* painter, const QPoint& point, const QSize& size) const
|
||||
{
|
||||
const QPixmap& pixmap = m_branchIcons[branchType];
|
||||
|
||||
pixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
const QSize sizeDelta = size - pixmap.size();
|
||||
const QPoint pointDelta = QPoint(sizeDelta.width() / 2, sizeDelta.height() / 2);
|
||||
painter->drawPixmap(point + pointDelta, pixmap);
|
||||
}
|
||||
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
#include "AssetBrowser/Views/moc_EntryDelegate.cpp"
|
||||
|
||||
+29
-1
@@ -27,9 +27,19 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
//! Type of branch icon the delegate should paint.
|
||||
enum EntryBranchType
|
||||
{
|
||||
First,
|
||||
Middle,
|
||||
Last,
|
||||
OneChild,
|
||||
Count
|
||||
};
|
||||
|
||||
class AssetBrowserFilterModel;
|
||||
|
||||
//! EntryDelegate draws a single item in AssetBrowser
|
||||
//! EntryDelegate draws a single item in AssetBrowser.
|
||||
class EntryDelegate
|
||||
: public QStyledItemDelegate
|
||||
{
|
||||
@@ -52,5 +62,23 @@ namespace AzToolsFramework
|
||||
//! Draw a thumbnail and return its width
|
||||
int DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const;
|
||||
};
|
||||
|
||||
//! SearchEntryDelegate draws a single item in AssetBrowserTableView.
|
||||
class SearchEntryDelegate
|
||||
: public EntryDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SearchEntryDelegate(QWidget* parent = nullptr);
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
|
||||
private:
|
||||
void LoadBranchPixMaps();
|
||||
void DrawBranchPixMap(EntryBranchType branchType, QPainter* painter, const QPoint& point, const QSize& size) const;
|
||||
|
||||
private:
|
||||
QMap<EntryBranchType, QPixmap> m_branchIcons;
|
||||
};
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace AzToolsFramework
|
||||
virtual AZ::EntityId GetFocusRoot() = 0;
|
||||
|
||||
//! Returns whether the entity id provided is part of the focused sub-tree.
|
||||
virtual bool IsInFocusSubTree(AZ::EntityId entityId) = 0;
|
||||
virtual bool IsInFocusSubTree(AZ::EntityId entityId) const = 0;
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ namespace AzToolsFramework
|
||||
return m_focusRoot;
|
||||
}
|
||||
|
||||
bool FocusModeSystemComponent::IsInFocusSubTree(AZ::EntityId entityId)
|
||||
bool FocusModeSystemComponent::IsInFocusSubTree(AZ::EntityId entityId) const
|
||||
{
|
||||
if (m_focusRoot == AZ::EntityId())
|
||||
{
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ namespace AzToolsFramework
|
||||
void SetFocusRoot(AZ::EntityId entityId) override;
|
||||
void ClearFocusRoot() override;
|
||||
AZ::EntityId GetFocusRoot() override;
|
||||
bool IsInFocusSubTree(AZ::EntityId entityId) override;
|
||||
bool IsInFocusSubTree(AZ::EntityId entityId) const override;
|
||||
|
||||
private:
|
||||
AZ::EntityId m_focusRoot;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace AzToolsFramework::Prefab
|
||||
{
|
||||
InstanceOptionalReference focusedInstance;
|
||||
|
||||
if (entityId == AZ::EntityId())
|
||||
if (!entityId.IsValid())
|
||||
{
|
||||
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
|
||||
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
|
||||
@@ -121,7 +121,7 @@ namespace AzToolsFramework::Prefab
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entityId == AZ::EntityId())
|
||||
if (!entityId.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -18,18 +18,19 @@ AzToolsFramework--EntityOutlinerWidget QTreeView
|
||||
selection-background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Entity Outliner handles hover and selected state of items via code,
|
||||
* so we need to override the AzQtComponents::Treeview style.
|
||||
*/
|
||||
AzToolsFramework--EntityOutlinerWidget QTreeView::branch:hover
|
||||
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:hover
|
||||
{
|
||||
background: rgba(255, 255, 255, 30);
|
||||
}
|
||||
|
||||
AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected
|
||||
, AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected
|
||||
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:selected
|
||||
, AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected:active
|
||||
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:selected:active
|
||||
{
|
||||
background: rgba(255, 255, 255, 45);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+18
-8
@@ -44,6 +44,7 @@
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/ComponentAssetMimeDataContainer.h>
|
||||
#include <AzToolsFramework/ToolsComponents/ComponentMimeData.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorEntityIdContainer.h>
|
||||
@@ -102,10 +103,14 @@ namespace AzToolsFramework
|
||||
EntityCompositionNotificationBus::Handler::BusConnect();
|
||||
AZ::EntitySystemBus::Handler::BusConnect();
|
||||
|
||||
m_editorEntityFrameworkInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get();
|
||||
m_editorEntityUiInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get();
|
||||
AZ_Assert(m_editorEntityUiInterface != nullptr,
|
||||
"EntityOutlinerListModel requires a EditorEntityUiInterface instance on Initialize.");
|
||||
|
||||
AZ_Assert(m_editorEntityFrameworkInterface != nullptr,
|
||||
"EntityOutlinerListModel requires a EditorEntityFrameworkInterface instance on Initialize.");
|
||||
m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
AZ_Assert(
|
||||
m_focusModeInterface != nullptr,
|
||||
"EntityOutlinerListModel requires a FocusModeInterface instance on Initialize.");
|
||||
}
|
||||
|
||||
int EntityOutlinerListModel::rowCount(const QModelIndex& parent) const
|
||||
@@ -279,7 +284,7 @@ namespace AzToolsFramework
|
||||
|
||||
QVariant EntityOutlinerListModel::GetEntityIcon(const AZ::EntityId& id) const
|
||||
{
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(id);
|
||||
auto entityUiHandler = m_editorEntityUiInterface->GetHandler(id);
|
||||
QIcon icon;
|
||||
|
||||
// Retrieve the icon from the handler
|
||||
@@ -316,7 +321,7 @@ namespace AzToolsFramework
|
||||
|
||||
QVariant EntityOutlinerListModel::GetEntityTooltip(const AZ::EntityId& id) const
|
||||
{
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(id);
|
||||
auto entityUiHandler = m_editorEntityUiInterface->GetHandler(id);
|
||||
QString tooltip;
|
||||
|
||||
// Retrieve the tooltip from the handler
|
||||
@@ -349,7 +354,7 @@ namespace AzToolsFramework
|
||||
QVariant EntityOutlinerListModel::dataForVisibility(const QModelIndex& index, int role) const
|
||||
{
|
||||
auto entityId = GetEntityFromIndex(index);
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId);
|
||||
auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
|
||||
|
||||
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
|
||||
{
|
||||
@@ -377,7 +382,7 @@ namespace AzToolsFramework
|
||||
QVariant EntityOutlinerListModel::dataForLock(const QModelIndex& index, int role) const
|
||||
{
|
||||
auto entityId = GetEntityFromIndex(index);
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId);
|
||||
auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
|
||||
|
||||
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
|
||||
{
|
||||
@@ -436,7 +441,7 @@ namespace AzToolsFramework
|
||||
if (value.canConvert<Qt::CheckState>())
|
||||
{
|
||||
const auto entityId = GetEntityFromIndex(index);
|
||||
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId);
|
||||
auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
|
||||
|
||||
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
|
||||
{
|
||||
@@ -532,6 +537,11 @@ namespace AzToolsFramework
|
||||
break;
|
||||
}
|
||||
|
||||
if (AZ::EntityId entityId = GetEntityFromIndex(index); !m_focusModeInterface->IsInFocusSubTree(entityId))
|
||||
{
|
||||
itemFlags &= !Qt::ItemIsEnabled;
|
||||
}
|
||||
|
||||
return itemFlags;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -36,6 +36,7 @@
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class EditorEntityUiInterface;
|
||||
class FocusModeInterface;
|
||||
|
||||
namespace EntityOutliner
|
||||
{
|
||||
@@ -273,7 +274,8 @@ namespace AzToolsFramework
|
||||
QVariant GetEntityIcon(const AZ::EntityId& id) const;
|
||||
QVariant GetEntityTooltip(const AZ::EntityId& id) const;
|
||||
|
||||
EditorEntityUiInterface* m_editorEntityFrameworkInterface = nullptr;
|
||||
EditorEntityUiInterface* m_editorEntityUiInterface = nullptr;
|
||||
FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
};
|
||||
|
||||
class EntityOutlinerCheckBox
|
||||
|
||||
+42
@@ -40,6 +40,8 @@ namespace AzToolsFramework
|
||||
"EntityOutlinerTreeView requires a EditorEntityFrameworkInterface instance on Construction.");
|
||||
|
||||
FocusModeNotificationBus::Handler::BusConnect();
|
||||
|
||||
viewport()->setMouseTracking(true);
|
||||
}
|
||||
|
||||
EntityOutlinerTreeView::~EntityOutlinerTreeView()
|
||||
@@ -63,6 +65,11 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::leaveEvent([[maybe_unused]] QEvent* event)
|
||||
{
|
||||
m_mousePosition = QPoint();
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
//postponing normal mouse pressed logic until mouse is released or dragged
|
||||
@@ -116,6 +123,8 @@ namespace AzToolsFramework
|
||||
setSelectionMode(selectionModeBefore);
|
||||
}
|
||||
|
||||
m_mousePosition = event->pos();
|
||||
|
||||
//process mouse movement as normal, potentially triggering drag and drop
|
||||
QTreeView::mouseMoveEvent(event);
|
||||
}
|
||||
@@ -176,12 +185,45 @@ namespace AzToolsFramework
|
||||
|
||||
void EntityOutlinerTreeView::drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const
|
||||
{
|
||||
const bool isEnabled = (this->model()->flags(index) & Qt::ItemIsEnabled);
|
||||
|
||||
const bool isSelected = selectionModel()->isSelected(index);
|
||||
const bool isHovered = (index == indexAt(m_mousePosition)) && isEnabled;
|
||||
|
||||
// Paint the branch Selection/Hover Rect
|
||||
PaintBranchSelectionHoverRect(painter, rect, isSelected, isHovered);
|
||||
|
||||
// Paint the branch background as defined by the entity's handler, or its closes ancestor's.
|
||||
PaintBranchBackground(painter, rect, index);
|
||||
|
||||
QTreeView::drawBranches(painter, rect, index);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::PaintBranchSelectionHoverRect(
|
||||
QPainter* painter, const QRect& rect, bool isSelected, bool isHovered) const
|
||||
{
|
||||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing, false);
|
||||
|
||||
if (isSelected || isHovered)
|
||||
{
|
||||
QPainterPath backgroundPath;
|
||||
QRect backgroundRect(rect);
|
||||
|
||||
backgroundPath.addRect(backgroundRect);
|
||||
|
||||
QColor backgroundColor = m_hoverColor;
|
||||
if (isSelected)
|
||||
{
|
||||
backgroundColor = m_selectedColor;
|
||||
}
|
||||
|
||||
painter->fillPath(backgroundPath, backgroundColor);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const
|
||||
{
|
||||
// Go through ancestors and add them to the stack
|
||||
|
||||
+3
@@ -61,6 +61,7 @@ namespace AzToolsFramework
|
||||
void startDrag(Qt::DropActions supportedActions) override;
|
||||
void dragMoveEvent(QDragMoveEvent* event) override;
|
||||
void dropEvent(QDropEvent* event) override;
|
||||
void leaveEvent(QEvent* event) override;
|
||||
|
||||
// FocusModeNotificationBus overrides ...
|
||||
void OnEditorFocusChanged(AZ::EntityId entityId) override;
|
||||
@@ -77,8 +78,10 @@ namespace AzToolsFramework
|
||||
void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions) override;
|
||||
|
||||
void PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const;
|
||||
void PaintBranchSelectionHoverRect(QPainter* painter, const QRect& rect, bool isSelected, bool isHovered) const;
|
||||
|
||||
QMouseEvent* m_queuedMouseEvent;
|
||||
QPoint m_mousePosition;
|
||||
bool m_draggingUnselectedItem; // This is set when an item is dragged outside its bounding box.
|
||||
|
||||
int m_expandOnlyDelay = -1;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AzFramework/Viewport/ViewportScreen.h>
|
||||
#include <AzFramework/Visibility/BoundsBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/API/EditorViewportIconDisplayInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorEntityIconComponentBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
@@ -112,6 +113,17 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
EditorHelpers::EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache)
|
||||
: m_entityDataCache(entityDataCache)
|
||||
{
|
||||
m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
AZ_Assert(
|
||||
m_focusModeInterface,
|
||||
"EditorHelpers - "
|
||||
"Focus Mode Interface could not be found. "
|
||||
"Check that it is being correctly initialized.");
|
||||
}
|
||||
|
||||
AZ::EntityId EditorHelpers::HandleMouseInteraction(
|
||||
const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
|
||||
{
|
||||
@@ -173,6 +185,12 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
// Verify if the entity Id corresponds to an entity that is focused; if not, halt selection.
|
||||
if (!m_focusModeInterface->IsInFocusSubTree(entityIdUnderCursor))
|
||||
{
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
return entityIdUnderCursor;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace AzFramework
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class EditorVisibleEntityDataCache;
|
||||
class FocusModeInterface;
|
||||
|
||||
namespace ViewportInteraction
|
||||
{
|
||||
@@ -38,10 +39,7 @@ namespace AzToolsFramework
|
||||
|
||||
//! An EditorVisibleEntityDataCache must be passed to EditorHelpers to allow it to
|
||||
//! efficiently read entity data without resorting to EBus calls.
|
||||
explicit EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache)
|
||||
: m_entityDataCache(entityDataCache)
|
||||
{
|
||||
}
|
||||
explicit EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache);
|
||||
EditorHelpers(const EditorHelpers&) = delete;
|
||||
EditorHelpers& operator=(const EditorHelpers&) = delete;
|
||||
~EditorHelpers() = default;
|
||||
@@ -62,5 +60,6 @@ namespace AzToolsFramework
|
||||
|
||||
private:
|
||||
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers.
|
||||
const FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class EditorFocusModeTests
|
||||
: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
m_app.Start(m_descriptor);
|
||||
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
|
||||
GenerateTestHierarchy();
|
||||
}
|
||||
|
||||
void GenerateTestHierarchy()
|
||||
{
|
||||
/*
|
||||
* City
|
||||
* |_ Street
|
||||
* |_ Car
|
||||
* | |_ Passenger
|
||||
* |_ SportsCar
|
||||
* |_ Passenger
|
||||
*/
|
||||
|
||||
m_entityMap["cityId"] = CreateEditorEntity("City", AZ::EntityId());
|
||||
m_entityMap["streetId"] = CreateEditorEntity("Street", m_entityMap["cityId"]);
|
||||
m_entityMap["carId"] = CreateEditorEntity("Car", m_entityMap["streetId"]);
|
||||
m_entityMap["passengerId1"] = CreateEditorEntity("Passenger", m_entityMap["carId"]);
|
||||
m_entityMap["sportsCarId"] = CreateEditorEntity("SportsCar", m_entityMap["streetId"]);
|
||||
m_entityMap["passengerId2"] = CreateEditorEntity("Passenger", m_entityMap["sportsCarId"]);
|
||||
}
|
||||
|
||||
AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId)
|
||||
{
|
||||
AZ::Entity* entity = nullptr;
|
||||
UnitTest::CreateDefaultEditorEntity(name, &entity);
|
||||
|
||||
// Parent
|
||||
AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId);
|
||||
|
||||
return entity->GetId();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_app.Stop();
|
||||
}
|
||||
|
||||
UnitTest::ToolsTestApplication m_app{ "EditorFocusModeTests" };
|
||||
AZ::ComponentApplication::Descriptor m_descriptor;
|
||||
AZStd::unordered_map<AZStd::string, AZ::EntityId> m_entityMap;
|
||||
};
|
||||
|
||||
TEST_F(EditorFocusModeTests, EditorFocusModeTests_SetFocus)
|
||||
{
|
||||
FocusModeInterface* focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
EXPECT_TRUE(focusModeInterface != nullptr);
|
||||
|
||||
focusModeInterface->SetFocusRoot(m_entityMap["carId"]);
|
||||
EXPECT_EQ(focusModeInterface->GetFocusRoot(), m_entityMap["carId"]);
|
||||
|
||||
focusModeInterface->ClearFocusRoot();
|
||||
EXPECT_EQ(focusModeInterface->GetFocusRoot(), AZ::EntityId());
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeTests, EditorFocusModeTests_IsInFocusSubTree)
|
||||
{
|
||||
FocusModeInterface* focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
EXPECT_TRUE(focusModeInterface != nullptr);
|
||||
|
||||
focusModeInterface->ClearFocusRoot();
|
||||
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
|
||||
|
||||
focusModeInterface->SetFocusRoot(m_entityMap["streetId"]);
|
||||
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
|
||||
|
||||
focusModeInterface->SetFocusRoot(m_entityMap["carId"]);
|
||||
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), false);
|
||||
|
||||
focusModeInterface->SetFocusRoot(m_entityMap["passengerId2"]);
|
||||
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false);
|
||||
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
|
||||
|
||||
focusModeInterface->ClearFocusRoot();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <Prefab/PrefabTestFixture.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class PrefabFocusTests
|
||||
: public PrefabTestFixture
|
||||
{
|
||||
protected:
|
||||
void GenerateTestHierarchy()
|
||||
{
|
||||
/*
|
||||
* City (Prefab Container)
|
||||
* |_ City
|
||||
* |_ Street (Prefab Container)
|
||||
* |_ Car (Prefab Container)
|
||||
* | |_ Passenger
|
||||
* |_ SportsCar (Prefab Container)
|
||||
* |_ Passenger
|
||||
*/
|
||||
|
||||
m_entityMap["passenger1"] = CreateEntity("Passenger1");
|
||||
m_entityMap["passenger2"] = CreateEntity("Passenger2");
|
||||
m_entityMap["city"] = CreateEntity("City");
|
||||
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded,
|
||||
AzToolsFramework::EntityList{ m_entityMap["passenger1"], m_entityMap["passenger2"], m_entityMap["city"] });
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> carInstance =
|
||||
m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger1"] }, {}, "test/car");
|
||||
ASSERT_TRUE(carInstance);
|
||||
m_instanceMap["car"] = carInstance.get();
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> sportsCarInstance =
|
||||
m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger2"] }, {}, "test/sportsCar");
|
||||
ASSERT_TRUE(sportsCarInstance);
|
||||
m_instanceMap["sportsCar"] = sportsCarInstance.get();
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> streetInstance =
|
||||
m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(carInstance), AZStd::move(sportsCarInstance) ), "test/street");
|
||||
ASSERT_TRUE(streetInstance);
|
||||
m_instanceMap["street"] = streetInstance.get();
|
||||
|
||||
m_rootInstance =
|
||||
m_prefabSystemComponent->CreatePrefab({ m_entityMap["city"] }, MakeInstanceList(AZStd::move(streetInstance)), "test/city");
|
||||
ASSERT_TRUE(m_rootInstance);
|
||||
m_instanceMap["city"] = m_rootInstance.get();
|
||||
}
|
||||
|
||||
AZStd::unordered_map<AZStd::string, AZ::Entity*> m_entityMap;
|
||||
AZStd::unordered_map<AZStd::string, Instance*> m_instanceMap;
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> m_rootInstance;
|
||||
};
|
||||
|
||||
TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab)
|
||||
{
|
||||
GenerateTestHierarchy();
|
||||
|
||||
PrefabFocusInterface* prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
|
||||
EXPECT_TRUE(prefabFocusInterface != nullptr);
|
||||
|
||||
// Verify FocusOnOwningPrefab works when passing the container entity of the root prefab.
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId());
|
||||
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId());
|
||||
|
||||
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
|
||||
EXPECT_TRUE(instance.has_value());
|
||||
EXPECT_EQ(&instance->get(), m_instanceMap["city"]);
|
||||
}
|
||||
|
||||
// Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab.
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["city"]->GetId());
|
||||
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId());
|
||||
|
||||
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
|
||||
EXPECT_TRUE(instance.has_value());
|
||||
EXPECT_EQ(&instance->get(), m_instanceMap["city"]);
|
||||
}
|
||||
|
||||
// Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab.
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["car"]->GetContainerEntityId());
|
||||
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId());
|
||||
|
||||
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
|
||||
EXPECT_TRUE(instance.has_value());
|
||||
EXPECT_EQ(&instance->get(), m_instanceMap["car"]);
|
||||
}
|
||||
|
||||
// Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab.
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["passenger1"]->GetId());
|
||||
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId());
|
||||
|
||||
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
|
||||
EXPECT_TRUE(instance.has_value());
|
||||
EXPECT_EQ(&instance->get(), m_instanceMap["car"]);
|
||||
}
|
||||
|
||||
// Verify FocusOnOwningPrefab points to the root prefab when the focus is cleared.
|
||||
{
|
||||
AzToolsFramework::PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
|
||||
AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
|
||||
AzToolsFramework::Prefab::InstanceOptionalReference rootPrefabInstance =
|
||||
prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
|
||||
EXPECT_TRUE(rootPrefabInstance.has_value());
|
||||
|
||||
prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId());
|
||||
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), rootPrefabInstance->get().GetTemplateId());
|
||||
|
||||
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
|
||||
EXPECT_TRUE(instance.has_value());
|
||||
EXPECT_EQ(&instance->get(), &rootPrefabInstance->get());
|
||||
}
|
||||
|
||||
m_rootInstance.release();
|
||||
}
|
||||
|
||||
TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused)
|
||||
{
|
||||
GenerateTestHierarchy();
|
||||
|
||||
PrefabFocusInterface* prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
|
||||
EXPECT_TRUE(prefabFocusInterface != nullptr);
|
||||
|
||||
// Verify IsOwningPrefabBeingFocused returns true for all entities in a focused prefab (container/nested)
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId());
|
||||
|
||||
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId()));
|
||||
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId()));
|
||||
}
|
||||
|
||||
// Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (ancestors/descendants)
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["street"]->GetContainerEntityId());
|
||||
|
||||
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["street"]->GetContainerEntityId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId()));
|
||||
}
|
||||
|
||||
// Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (siblings)
|
||||
{
|
||||
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["sportsCar"]->GetContainerEntityId());
|
||||
|
||||
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["sportsCar"]->GetContainerEntityId()));
|
||||
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger2"]->GetId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId()));
|
||||
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId()));
|
||||
}
|
||||
|
||||
m_rootInstance.release();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,6 +34,7 @@ set(FILES
|
||||
EntityTestbed.h
|
||||
FileFunc.cpp
|
||||
FingerprintingTests.cpp
|
||||
FocusMode/EditorFocusModeTests.cpp
|
||||
GenericComponentWrapperTest.cpp
|
||||
InstanceDataHierarchy.cpp
|
||||
IntegerPrimtitiveTestConfig.h
|
||||
@@ -50,6 +51,7 @@ set(FILES
|
||||
Prefab/Benchmark/PrefabLoadBenchmarks.cpp
|
||||
Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp
|
||||
Prefab/Benchmark/SpawnableCreateBenchmarks.cpp
|
||||
Prefab/PrefabFocus/PrefabFocusTests.cpp
|
||||
Prefab/MockPrefabFileIOActionValidator.cpp
|
||||
Prefab/MockPrefabFileIOActionValidator.h
|
||||
Prefab/PrefabDuplicateTests.cpp
|
||||
|
||||
Reference in New Issue
Block a user