Project Manager: Feature tag filtering for header of the gem catalog (#1956)

* [LYN-4440] Added new feature tag remove icon

Signed-off-by: Benjamin Jillich <jillich@amazon.com>

* [LYN-4440] Added new gem filter tag widget

Signed-off-by: Benjamin Jillich <jillich@amazon.com>

* [LYN-4440] Added feature tag widget used for showing the filtered tags in the gem catalog header

Signed-off-by: Benjamin Jillich <jillich@amazon.com>

* [LYN-4440] Added filter tag widget container to the gem catalog header and connected it to the gem model

Signed-off-by: Benjamin Jillich <jillich@amazon.com>

* [LYN-4440] Syncing the feature tag filters on the left panel with the tag widgets in the header and styling the item delegates

Signed-off-by: Benjamin Jillich <jillich@amazon.com>
This commit is contained in:
Benjamin Jillich
2021-07-09 08:18:35 -07:00
committed by GitHub
parent 5b44ea9b9a
commit 595ac3fb08
10 changed files with 213 additions and 8 deletions
@@ -0,0 +1,96 @@
/*
* 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 <GemCatalog/GemFilterTagWidget.h>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QSpacerItem>
#include <QWidget>
namespace O3DE::ProjectManager
{
FilterTagWidget::FilterTagWidget(const QString& text, QWidget* parent)
: QFrame(parent)
{
setFrameShape(QFrame::NoFrame);
auto* layout = new QHBoxLayout();
layout->setContentsMargins(6, 5, 4, 4);
layout->setSpacing(2);
setLayout(layout);
setStyleSheet("background-color: #555555;");
m_textLabel = new QLabel();
m_textLabel->setObjectName("FilterTagWidgetTextLabel");
m_textLabel->setText(text);
layout->addWidget(m_textLabel);
m_closeButton = new QPushButton();
m_closeButton->setFlat(true);
m_closeButton->setIcon(QIcon(":/FeatureTagClose.svg"));
m_closeButton->setIconSize(QSize(12, 12));
m_closeButton->setStyleSheet("QPushButton { background-color: transparent; border: 0px }");
layout->addWidget(m_closeButton);
connect(m_closeButton, &QPushButton::clicked, this, [=]{ emit RemoveClicked(); });
}
QString FilterTagWidget::text() const
{
return m_textLabel->text();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FilterTagWidgetContainer::FilterTagWidgetContainer(QWidget* parent)
: QWidget(parent)
{
m_layout = new QHBoxLayout();
m_layout->setMargin(0);
m_layout->setSpacing(0);
setLayout(m_layout);
}
void FilterTagWidgetContainer::Reinit(const QVector<QString>& tags)
{
if (m_widget)
{
// Hide the old widget and request deletion.
m_widget->hide();
m_widget->deleteLater();
}
m_widget = new QWidget(this);
QHBoxLayout* hLayout = new QHBoxLayout();
hLayout->setAlignment(Qt::AlignLeft);
hLayout->setMargin(0);
hLayout->setSpacing(8);
const int numTags = tags.count();
for (int i = 0; i < numTags; ++i)
{
FilterTagWidget* tagWidget = new FilterTagWidget(tags[i]);
// Add the tag widget to the current row.
hLayout->addWidget(tagWidget);
// Connect the clicked event of the close button of the tag widget to the remove tag function in the container.
connect(tagWidget, &FilterTagWidget::RemoveClicked, this, [this, tagWidget]{ emit TagRemoved(tagWidget->text()); });
}
QWidget* spacerWidget = new QWidget();
spacerWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
hLayout->addWidget(spacerWidget);
m_widget->setLayout(hLayout);
m_layout->addWidget(m_widget);
setFixedHeight(30);
}
} // namespace O3DE::ProjectManager
@@ -0,0 +1,57 @@
/*
* 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 <QFrame>
#include <QString>
#include <QVector>
#endif
QT_FORWARD_DECLARE_CLASS(QHBoxLayout)
QT_FORWARD_DECLARE_CLASS(QLabel)
QT_FORWARD_DECLARE_CLASS(QPushButton)
QT_FORWARD_DECLARE_CLASS(QWidget)
namespace O3DE::ProjectManager
{
class FilterTagWidget
: public QFrame
{
Q_OBJECT
public:
FilterTagWidget(const QString& text, QWidget* parent = nullptr);
QString text() const;
signals:
void RemoveClicked();
private:
QLabel* m_textLabel = nullptr;
QPushButton* m_closeButton = nullptr;
};
// Horizontally expanding filter tag container widget
class FilterTagWidgetContainer
: public QWidget
{
Q_OBJECT
public:
FilterTagWidgetContainer(QWidget* parent = nullptr);
void Reinit(const QVector<QString>& tags);
signals:
void TagRemoved(QString tagName);
private:
QWidget* m_widget = nullptr;
QHBoxLayout* m_layout = nullptr;
};
} // namespace O3DE::ProjectManager
@@ -14,6 +14,7 @@
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QSignalBlocker>
namespace O3DE::ProjectManager
{
@@ -485,6 +486,7 @@ namespace O3DE::ProjectManager
const QString& feature = elementNames[i];
QAbstractButton* button = buttons[i];
// Adjust the proxy model and enable or disable the clicked feature used for filtering.
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
{
QSet<QString> features = m_filterProxyModel->GetFeatures();
@@ -498,6 +500,15 @@ namespace O3DE::ProjectManager
}
m_filterProxyModel->SetFeatures(features);
});
// Sync the UI state with the proxy model filtering.
connect(m_filterProxyModel, &GemSortFilterProxyModel::OnInvalidated, this, [=]
{
const QSet<QString>& filteredFeatureTags = m_filterProxyModel->GetFeatures();
const bool isChecked = filteredFeatureTags.contains(button->text());
QSignalBlocker signalsBlocker(button);
button->setChecked(isChecked);
});
}
}
} // namespace O3DE::ProjectManager
@@ -102,9 +102,11 @@ namespace O3DE::ProjectManager
// In case there are feature tags displayed at the bottom, decrease the size of the summary text field.
const QStringList featureTags = GemModel::GetFeatures(modelIndex);
const int summaryHeight = contentRect.height() - (!featureTags.empty() * 30);
const int featureTagAreaHeight = 30;
const int summaryHeight = contentRect.height() - (!featureTags.empty() * featureTagAreaHeight);
const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - s_itemMargins.right() * 3,
const int additionalSummarySpacing = s_itemMargins.right() * 3;
const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - additionalSummarySpacing,
summaryHeight);
const QRect summaryRect = QRect(/*topLeft=*/QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), summarySize);
@@ -7,10 +7,13 @@
#include <GemCatalog/GemItemDelegate.h>
#include <GemCatalog/GemListHeaderWidget.h>
#include <QStandardItemModel>
#include <AzQtComponents/Components/TagSelector.h>
#include <QAbstractItemModel>
#include <QItemSelectionModel>
#include <QLabel>
#include <QVBoxLayout>
#include <QSpacerItem>
#include <QStandardItemModel>
#include <QVBoxLayout>
namespace O3DE::ProjectManager
{
@@ -23,11 +26,34 @@ namespace O3DE::ProjectManager
setStyleSheet("background-color: #333333;");
vLayout->addSpacing(20);
vLayout->addSpacing(13);
// Top section
QHBoxLayout* topLayout = new QHBoxLayout();
topLayout->addSpacing(16);
topLayout->setMargin(0);
auto* tagWidget = new FilterTagWidgetContainer();
// Adjust the proxy model and disable the given feature used for filtering.
connect(tagWidget, &FilterTagWidgetContainer::TagRemoved, this, [=](QString tagName)
{
QSet<QString> filteredFeatureTags = proxyModel->GetFeatures();
filteredFeatureTags.remove(tagName);
proxyModel->SetFeatures(filteredFeatureTags);
});
// Reinitialize the tag widget in case the filter in the proxy model got invalided.
connect(proxyModel, &GemSortFilterProxyModel::OnInvalidated, this, [=]
{
const QSet<QString>& tagSet = proxyModel->GetFeatures();
QVector<QString> sortedTags(tagSet.begin(), tagSet.end());
std::sort(sortedTags.begin(), sortedTags.end());
tagWidget->Reinit(sortedTags);
});
topLayout->addWidget(tagWidget);
topLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
QLabel* showCountLabel = new QLabel();
@@ -43,7 +69,7 @@ namespace O3DE::ProjectManager
vLayout->addLayout(topLayout);
vLayout->addSpacing(20);
vLayout->addSpacing(13);
// Separating line
QFrame* hLine = new QFrame();
@@ -8,9 +8,8 @@
#pragma once
#if !defined(Q_MOC_RUN)
#include <GemCatalog/GemFilterTagWidget.h>
#include <GemCatalog/GemSortFilterProxyModel.h>
#include <QAbstractItemModel>
#include <QItemSelectionModel>
#include <QFrame>
#endif