diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg
new file mode 100644
index 0000000000..f1d36d3e41
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg
@@ -0,0 +1,7 @@
+
diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg
new file mode 100644
index 0000000000..9fc9fe52c2
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg
@@ -0,0 +1,5 @@
+
diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg
new file mode 100644
index 0000000000..7a61db38e0
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg
@@ -0,0 +1,6 @@
+
diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg
new file mode 100644
index 0000000000..c6fb977c52
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg
@@ -0,0 +1,6 @@
+
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp
index 469a235b9f..ec709aef8a 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp
@@ -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))
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp
index 37091c11e2..217e282a37 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp
@@ -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)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h
index 94e9bdc4e4..b4eca59cef 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h
@@ -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 m_tableModel = nullptr;
- QPointer m_sourceFilterModel = nullptr;
- EntryDelegate* m_delegate = nullptr;
+ QPointer m_tableModel;
+ QPointer m_sourceFilterModel;
+ SearchEntryDelegate* m_delegate = nullptr;
private Q_SLOTS:
void OnContextMenu(const QPoint& point);
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp
index 29324c612c..755c59b55b 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp
@@ -11,12 +11,13 @@
#include
#include
#include
-
+#include
#include
#include
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer' 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
#include
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(AssetBrowserEntry::Column::Name)
? qvariant_cast(entry->data(aznumeric_cast(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())
+ {
+ 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(data);
+ auto sourceEntry = azrtti_cast(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(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(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(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(indexBelow.data(AssetBrowserModel::Roles::EntryRole));
+ auto belowEntry = qvariant_cast(indexAbove.data(AssetBrowserModel::Roles::EntryRole));
+
+ auto aboveSourceEntry = azrtti_cast(aboveEntry);
+ auto belowSourceEntry = azrtti_cast(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(AssetBrowserEntry::Column::Name)
+ ? qvariant_cast(entry->data(aznumeric_cast(AssetBrowserEntry::Column::Name)))
+ : qvariant_cast(entry->data(aznumeric_cast(AssetBrowserEntry::Column::Path)));
+
+ style->drawItemText(
+ painter, remainingRect, option.displayAlignment, actualPalette, isEnabled, displayString,
+ isSelected ? QPalette::HighlightedText : QPalette::Text);
+ }
+ }
+
+ void SearchEntryDelegate::LoadBranchPixMaps()
+ {
+ AZ::IO::BasicPath 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(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"
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h
index 643bedec7c..ac68c19248 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h
@@ -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 m_branchIcons;
+ };
} // namespace AssetBrowser
} // namespace AzToolsFramework