Product/Source differentiation AssetBrowser Search View. (#4144)

* Added whole row highlight

Signed-off-by: igarri <igarri@amazon.com>

* Applied code review changes

Signed-off-by: igarri <igarri@amazon.com>

* Addressed code review comments

Signed-off-by: igarri <igarri@amazon.com>

* fixed QPointers

Signed-off-by: igarri <igarri@amazon.com>

* Added indentation to child items

Signed-off-by: igarri <igarri@amazon.com>

* Added Branch Icons

Signed-off-by: igarri <igarri@amazon.com>

* Loading icons and keeping a reference.

Signed-off-by: igarri <igarri@amazon.com>

* Fixed typos

Signed-off-by: igarri <igarri@amazon.com>

* Fixed TableView Header

Signed-off-by: igarri <igarri@amazon.com>

* Cleaned up Delegate Paint

Signed-off-by: igarri <igarri@amazon.com>

* Fixed view style

Signed-off-by: igarri <igarri@amazon.com>

* small tweaks

Signed-off-by: igarri <igarri@amazon.com>

* Added Assert

Signed-off-by: igarri <igarri@amazon.com>

* Small tweak in Table Model

Signed-off-by: igarri <igarri@amazon.com>

* Code Review Feedback

Signed-off-by: igarri <igarri@amazon.com>

* Code review Comments

Signed-off-by: igarri <igarri@amazon.com>

* Removed Comment

Signed-off-by: igarri <igarri@amazon.com>
monroegm-disable-blank-issue-2
AMZN-Igarri 4 years ago committed by GitHub
parent 2ce7bbd945
commit c75f3690da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,7 @@
<svg width="24" height="33" viewBox="0 0 24 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" y="7" width="2" height="12" fill="#808080"/>
<rect x="5" y="19" width="2" height="14" fill="#808080"/>
<rect x="17" y="16" width="2" height="12" transform="rotate(90 17 16)" fill="#808080"/>
<circle cx="6" cy="6" r="2" fill="#808080"/>
<circle cx="18" cy="17" r="2" fill="#808080"/>
</svg>

After

Width:  |  Height:  |  Size: 398 B

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" width="2" height="12" fill="grey"/>
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="grey"/>
<circle cx="18" cy="13" r="2" fill="grey"/>
</svg>

After

Width:  |  Height:  |  Size: 280 B

@ -0,0 +1,6 @@
<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" width="2" height="12" fill="grey"/>
<rect x="5" y="14" width="2" height="12" fill="grey"/>
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="grey"/>
<circle cx="18" cy="13" r="2" fill="grey"/>
</svg>

After

Width:  |  Height:  |  Size: 335 B

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" y="7" width="2" height="7" fill="#808080"/>
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="#808080"/>
<circle cx="6" cy="6" r="2" fill="#808080"/>
<circle cx="18" cy="13" r="2" fill="#808080"/>
</svg>

After

Width:  |  Height:  |  Size: 339 B

@ -138,7 +138,13 @@ namespace AzToolsFramework
m_indexMap[row] = index; m_indexMap[row] = index;
m_rowMap[index] = row; m_rowMap[index] = row;
++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)) if (model->hasChildren(index))

@ -29,20 +29,20 @@ namespace AzToolsFramework
{ {
AssetBrowserTableView::AssetBrowserTableView(QWidget* parent) AssetBrowserTableView::AssetBrowserTableView(QWidget* parent)
: AzQtComponents::TableView(parent) : AzQtComponents::TableView(parent)
, m_delegate(new EntryDelegate(this)) , m_delegate(new SearchEntryDelegate(this))
{ {
setSortingEnabled(true); setSortingEnabled(false);
setItemDelegate(m_delegate); setItemDelegate(m_delegate);
setRootIsDecorated(false); setRootIsDecorated(false);
//Styling the header aligning text to the left and using a bold font. //Styling the header aligning text to the left and using a bold font.
header()->setDefaultAlignment(Qt::AlignLeft); header()->setDefaultAlignment(Qt::AlignLeft);
header()->setStyleSheet("QHeaderView { font-weight: bold; }"); header()->setStyleSheet("QHeaderView { font-weight: bold; };");
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
setMouseTracking(true); setMouseTracking(true);
setSortingEnabled(false);
setSelectionMode(QAbstractItemView::SingleSelection); setSelectionMode(QAbstractItemView::SingleSelection);
connect(this, &AzQtComponents::TableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu); connect(this, &AzQtComponents::TableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu);
@ -67,6 +67,8 @@ namespace AzToolsFramework
header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch); header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch); header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
header()->setSortIndicatorShown(false);
header()->setSectionsClickable(false);
} }
void AssetBrowserTableView::SetName(const QString& name) void AssetBrowserTableView::SetName(const QString& name)

@ -26,7 +26,7 @@ namespace AzToolsFramework
class AssetBrowserEntry; class AssetBrowserEntry;
class AssetBrowserTableModel; class AssetBrowserTableModel;
class AssetBrowserFilterModel; class AssetBrowserFilterModel;
class EntryDelegate; class SearchEntryDelegate;
class AssetBrowserTableView //! Table view that displays the asset browser entries in a list. class AssetBrowserTableView //! Table view that displays the asset browser entries in a list.
: public AzQtComponents::TableView : public AzQtComponents::TableView
@ -67,9 +67,9 @@ namespace AzToolsFramework
private: private:
QString m_name; QString m_name;
QPointer<AssetBrowserTableModel> m_tableModel = nullptr; QPointer<AssetBrowserTableModel> m_tableModel;
QPointer<AssetBrowserFilterModel> m_sourceFilterModel = nullptr; QPointer<AssetBrowserFilterModel> m_sourceFilterModel;
EntryDelegate* m_delegate = nullptr; SearchEntryDelegate* m_delegate = nullptr;
private Q_SLOTS: private Q_SLOTS:
void OnContextMenu(const QPoint& point); void OnContextMenu(const QPoint& point);

@ -11,12 +11,13 @@
#include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h> #include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h> #include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <AzToolsFramework/AssetBrowser/Views/EntryDelegate.h> #include <AzToolsFramework/AssetBrowser/Views/EntryDelegate.h>
#include <AzCore/Utils/Utils.h>
#include <AzQtComponents/Components/StyledBusyLabel.h> #include <AzQtComponents/Components/StyledBusyLabel.h>
#include <QApplication> #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' 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) // 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning)
#include <QAbstractItemView>
#include <QPainter> #include <QPainter>
AZ_POP_DISABLE_WARNING AZ_POP_DISABLE_WARNING
@ -24,8 +25,13 @@ namespace AzToolsFramework
{ {
namespace AssetBrowser namespace AssetBrowser
{ {
const int ENTRY_SPACING_LEFT_PIXELS = 8; static constexpr const char* TreeIconPathFirst = "Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg";
const int ENTRY_ICON_MARGIN_LEFT_PIXELS = 2; 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) EntryDelegate::EntryDelegate(QWidget* parent)
: QStyledItemDelegate(parent) : QStyledItemDelegate(parent)
@ -62,7 +68,7 @@ namespace AzToolsFramework
// Draw main entry thumbnail. // Draw main entry thumbnail.
QRect remainingRect(option.rect); 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); 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 // 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(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) 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::Name)))
@ -148,7 +154,162 @@ namespace AzToolsFramework
return m_iconSize; 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 } // namespace AzToolsFramework
#include "AssetBrowser/Views/moc_EntryDelegate.cpp" #include "AssetBrowser/Views/moc_EntryDelegate.cpp"

@ -27,9 +27,19 @@ namespace AzToolsFramework
{ {
namespace AssetBrowser namespace AssetBrowser
{ {
//! Type of branch icon the delegate should paint.
enum EntryBranchType
{
First,
Middle,
Last,
OneChild,
Count
};
class AssetBrowserFilterModel; class AssetBrowserFilterModel;
//! EntryDelegate draws a single item in AssetBrowser //! EntryDelegate draws a single item in AssetBrowser.
class EntryDelegate class EntryDelegate
: public QStyledItemDelegate : public QStyledItemDelegate
{ {
@ -52,5 +62,23 @@ namespace AzToolsFramework
//! Draw a thumbnail and return its width //! Draw a thumbnail and return its width
int DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const; 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 AssetBrowser
} // namespace AzToolsFramework } // namespace AzToolsFramework

Loading…
Cancel
Save