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:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user