forked from qt-creator/qt-creator
Examples: Limit categories to single row and allow showing all
Limit the items shown for categories to a single row (two rows for first, "featured" category), and add a "Show All" link/button in the heading, that shows all items in that category only (with a "Back" button). The "Search in Examples" input ignores categories. Change-Id: I7c8561a306ad86c3b537587621d3fd030cd08af8 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/fancylineedit.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/stylehelper.h>
|
||||
#include <utils/theme/theme.h>
|
||||
@@ -25,9 +26,11 @@
|
||||
|
||||
#include <qdrawutil.h>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
namespace Core {
|
||||
|
||||
using namespace Utils;
|
||||
using namespace WelcomePageHelpers;
|
||||
|
||||
static QColor themeColor(Theme::Color role)
|
||||
{
|
||||
@@ -123,6 +126,17 @@ SectionGridView::SectionGridView(QWidget *parent)
|
||||
: GridView(parent)
|
||||
{}
|
||||
|
||||
void SectionGridView::setMaxRows(std::optional<int> max)
|
||||
{
|
||||
m_maxRows = max;
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
std::optional<int> SectionGridView::maxRows() const
|
||||
{
|
||||
return m_maxRows;
|
||||
}
|
||||
|
||||
bool SectionGridView::hasHeightForWidth() const
|
||||
{
|
||||
return true;
|
||||
@@ -132,7 +146,16 @@ int SectionGridView::heightForWidth(int width) const
|
||||
{
|
||||
const int columnCount = width / Core::ListItemDelegate::GridItemWidth;
|
||||
const int rowCount = (model()->rowCount() + columnCount - 1) / columnCount;
|
||||
return rowCount * Core::ListItemDelegate::GridItemHeight;
|
||||
const int maxRowCount = m_maxRows ? std::min(*m_maxRows, rowCount) : rowCount;
|
||||
return maxRowCount * Core::ListItemDelegate::GridItemHeight;
|
||||
}
|
||||
|
||||
void SectionGridView::wheelEvent(QWheelEvent *e)
|
||||
{
|
||||
if (m_maxRows) // circumvent scrolling of the list view
|
||||
QWidget::wheelEvent(e);
|
||||
else
|
||||
GridView::wheelEvent(e);
|
||||
}
|
||||
|
||||
const QSize ListModel::defaultImageSize(214, 160);
|
||||
@@ -646,7 +669,7 @@ SectionedGridView::SectionedGridView(QWidget *parent)
|
||||
auto sectionedView = new QWidget;
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addStretch();
|
||||
layout->addStretch(1);
|
||||
sectionedView->setLayout(layout);
|
||||
area->setWidget(sectionedView);
|
||||
|
||||
@@ -678,8 +701,12 @@ void SectionedGridView::setPixmapFunction(const Core::ListModel::PixmapFunction
|
||||
void SectionedGridView::setSearchString(const QString &searchString)
|
||||
{
|
||||
if (searchString.isEmpty()) {
|
||||
// back to sectioned view
|
||||
setCurrentIndex(0);
|
||||
// back to previous view
|
||||
m_allItemsView.reset();
|
||||
if (m_zoomedInWidget)
|
||||
setCurrentWidget(m_zoomedInWidget);
|
||||
else
|
||||
setCurrentIndex(0);
|
||||
return;
|
||||
}
|
||||
if (!m_allItemsView) {
|
||||
@@ -711,13 +738,19 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QList<Lis
|
||||
gridView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
gridView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
gridView->setModel(model);
|
||||
gridView->setMaxRows(section.maxRows);
|
||||
|
||||
m_sectionModels.insert(section, model);
|
||||
const auto it = m_gridViews.insert(section, gridView);
|
||||
|
||||
auto sectionLabel = new QLabel(section.name);
|
||||
using namespace Layouting;
|
||||
auto seeAllLink = new QLabel("<a href=\"link\">" + Tr::tr("Show All") + " ></a>", this);
|
||||
seeAllLink->setVisible(gridView->maxRows().has_value());
|
||||
connect(seeAllLink, &QLabel::linkActivated, this, [this, section] { zoomInSection(section); });
|
||||
QWidget *sectionLabel = Column{hr, Row{section.name, st, seeAllLink, Space(HSpacing)}}.emerge(
|
||||
Layouting::WithoutMargins);
|
||||
m_sectionLabels.append(sectionLabel);
|
||||
sectionLabel->setContentsMargins(0, Core::WelcomePageHelpers::ItemGap, 0, 0);
|
||||
sectionLabel->setContentsMargins(0, ItemGap, 0, 0);
|
||||
sectionLabel->setFont(Core::WelcomePageHelpers::brandFont());
|
||||
auto scrollArea = qobject_cast<QScrollArea *>(widget(0));
|
||||
auto vbox = qobject_cast<QVBoxLayout *>(scrollArea->widget()->layout());
|
||||
@@ -753,4 +786,47 @@ void SectionedGridView::clear()
|
||||
m_allItemsView.reset();
|
||||
}
|
||||
|
||||
void SectionedGridView::zoomInSection(const Section §ion)
|
||||
{
|
||||
auto zoomedInWidget = new QWidget(this);
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
zoomedInWidget->setLayout(layout);
|
||||
|
||||
using namespace Layouting;
|
||||
auto backLink = new QLabel("<a href=\"link\">< " + Tr::tr("Back") + "</a>", zoomedInWidget);
|
||||
connect(backLink, &QLabel::linkActivated, this, [this, zoomedInWidget] {
|
||||
removeWidget(zoomedInWidget);
|
||||
delete zoomedInWidget;
|
||||
setCurrentIndex(0);
|
||||
});
|
||||
QWidget *sectionLabel = Column{hr, Row{section.name, st, backLink, Space(HSpacing)}}.emerge(
|
||||
Layouting::WithoutMargins);
|
||||
sectionLabel->setContentsMargins(0, ItemGap, 0, 0);
|
||||
sectionLabel->setFont(Core::WelcomePageHelpers::brandFont());
|
||||
|
||||
auto gridView = new GridView(zoomedInWidget);
|
||||
gridView->setItemDelegate(m_itemDelegate);
|
||||
gridView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
gridView->setModel(m_sectionModels.value(section));
|
||||
|
||||
layout->addWidget(sectionLabel);
|
||||
layout->addWidget(gridView);
|
||||
|
||||
m_zoomedInWidget = zoomedInWidget;
|
||||
addWidget(zoomedInWidget);
|
||||
setCurrentWidget(zoomedInWidget);
|
||||
}
|
||||
|
||||
Section::Section(const QString &name, int priority)
|
||||
: name(name)
|
||||
, priority(priority)
|
||||
{}
|
||||
|
||||
Section::Section(const QString &name, int priority, std::optional<int> maxRows)
|
||||
: name(name)
|
||||
, priority(priority)
|
||||
, maxRows(maxRows)
|
||||
{}
|
||||
|
||||
} // namespace Core
|
||||
|
@@ -51,8 +51,16 @@ class CORE_EXPORT SectionGridView : public GridView
|
||||
public:
|
||||
explicit SectionGridView(QWidget *parent);
|
||||
|
||||
bool hasHeightForWidth() const;
|
||||
int heightForWidth(int width) const;
|
||||
void setMaxRows(std::optional<int> max);
|
||||
std::optional<int> maxRows() const;
|
||||
|
||||
bool hasHeightForWidth() const override;
|
||||
int heightForWidth(int width) const override;
|
||||
|
||||
void wheelEvent(QWheelEvent *e) override;
|
||||
|
||||
private:
|
||||
std::optional<int> m_maxRows;
|
||||
};
|
||||
|
||||
using OptModelIndex = std::optional<QModelIndex>;
|
||||
@@ -165,6 +173,9 @@ private:
|
||||
class CORE_EXPORT Section
|
||||
{
|
||||
public:
|
||||
Section(const QString &name, int priority);
|
||||
Section(const QString &name, int priority, std::optional<int> maxRows);
|
||||
|
||||
friend bool operator<(const Section &lhs, const Section &rhs)
|
||||
{
|
||||
if (lhs.priority < rhs.priority)
|
||||
@@ -179,6 +190,7 @@ public:
|
||||
|
||||
QString name;
|
||||
int priority;
|
||||
std::optional<int> maxRows;
|
||||
};
|
||||
|
||||
class CORE_EXPORT SectionedGridView : public QStackedWidget
|
||||
@@ -196,11 +208,14 @@ public:
|
||||
void clear();
|
||||
|
||||
private:
|
||||
void zoomInSection(const Section §ion);
|
||||
|
||||
QMap<Section, Core::ListModel *> m_sectionModels;
|
||||
QList<QWidget *> m_sectionLabels;
|
||||
QMap<Section, Core::GridView *> m_gridViews;
|
||||
std::unique_ptr<Core::ListModel> m_allItemsModel;
|
||||
std::unique_ptr<Core::GridView> m_allItemsView;
|
||||
QPointer<QWidget> m_zoomedInWidget;
|
||||
Core::ListModel::PixmapFunction m_pixmapFunction;
|
||||
QAbstractItemDelegate *m_itemDelegate = nullptr;
|
||||
};
|
||||
|
@@ -329,7 +329,7 @@ static bool sortByHighlightedAndName(ExampleItem *first, ExampleItem *second)
|
||||
return first->name.compare(second->name, Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
|
||||
static QList<std::pair<QString, QList<ExampleItem *>>> getCategories(
|
||||
static QList<std::pair<Section, QList<ExampleItem *>>> getCategories(
|
||||
const QList<ExampleItem *> &items)
|
||||
{
|
||||
static const QString otherDisplayName = Tr::tr("Other", "Category for all other examples");
|
||||
@@ -345,7 +345,7 @@ static QList<std::pair<QString, QList<ExampleItem *>>> getCategories(
|
||||
other.append(item);
|
||||
}
|
||||
}
|
||||
QList<std::pair<QString, QList<ExampleItem *>>> categories;
|
||||
QList<std::pair<Section, QList<ExampleItem *>>> categories;
|
||||
if (categoryMap.isEmpty()) {
|
||||
// The example set doesn't define categories. Consider the "highlighted" ones as "featured"
|
||||
QList<ExampleItem *> featured;
|
||||
@@ -354,15 +354,19 @@ static QList<std::pair<QString, QList<ExampleItem *>>> getCategories(
|
||||
return i->isHighlighted;
|
||||
});
|
||||
if (!featured.isEmpty())
|
||||
categories.append({Tr::tr("Featured", "Category for highlighted examples"), featured});
|
||||
categories.append(
|
||||
{{Tr::tr("Featured", "Category for highlighted examples"), 0}, featured});
|
||||
if (!allOther.isEmpty())
|
||||
categories.append({otherDisplayName, allOther});
|
||||
categories.append({{otherDisplayName, 1}, allOther});
|
||||
} else {
|
||||
int index = 0;
|
||||
const auto end = categoryMap.constKeyValueEnd();
|
||||
for (auto it = categoryMap.constKeyValueBegin(); it != end; ++it)
|
||||
categories.append(*it);
|
||||
for (auto it = categoryMap.constKeyValueBegin(); it != end; ++it) {
|
||||
categories.append({{it->first, index, /*maxRows=*/index == 0 ? 2 : 1}, it->second});
|
||||
++index;
|
||||
}
|
||||
if (!other.isEmpty())
|
||||
categories.append({otherDisplayName, other});
|
||||
categories.append({{otherDisplayName, index, /*maxRows=*/1}, other});
|
||||
}
|
||||
const auto end = categories.end();
|
||||
for (auto it = categories.begin(); it != end; ++it)
|
||||
@@ -414,9 +418,9 @@ void ExamplesViewController::updateExamples()
|
||||
}
|
||||
}
|
||||
|
||||
const QList<std::pair<QString, QList<ExampleItem *>>> sections = getCategories(items);
|
||||
const QList<std::pair<Section, QList<ExampleItem *>>> sections = getCategories(items);
|
||||
for (int i = 0; i < sections.size(); ++i) {
|
||||
m_view->addSection({sections.at(i).first, i},
|
||||
m_view->addSection(sections.at(i).first,
|
||||
static_container_cast<ListItem *>(sections.at(i).second));
|
||||
}
|
||||
}
|
||||
@@ -519,7 +523,7 @@ QStringList ExampleSetModel::exampleSources(QString *examplesInstallPath, QStrin
|
||||
const QStringList demosPattern(QLatin1String("demos-manifest.xml"));
|
||||
QFileInfoList fis;
|
||||
const QFileInfoList subDirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (QFileInfo subDir : subDirs) {
|
||||
for (const QFileInfo &subDir : subDirs) {
|
||||
fis << QDir(subDir.absoluteFilePath()).entryInfoList(examplesPattern);
|
||||
fis << QDir(subDir.absoluteFilePath()).entryInfoList(demosPattern);
|
||||
}
|
||||
|
Reference in New Issue
Block a user