Qt: Add search/filter toolbar

This commit is contained in:
Connor McLaughlin 2022-07-09 18:52:33 +10:00 committed by refractionpcsx2
parent 1cee55bf45
commit 7d71954674
17 changed files with 430 additions and 60 deletions

View File

@ -269,30 +269,19 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
{ {
case Column_Type: case Column_Type:
{ {
switch (ge->type) return m_type_pixmaps[static_cast<u32>(ge->type)];
{
case GameList::EntryType::PS1Disc:
case GameList::EntryType::PS2Disc:
// return ((ge->settings.GetUserSettingsCount() > 0) ? m_type_disc_with_settings_pixmap : // m_type_disc_pixmap);
return m_type_disc_pixmap;
case GameList::EntryType::Playlist:
return m_type_playlist_pixmap;
case GameList::EntryType::ELF:
default:
return m_type_exe_pixmap;
}
} }
case Column_Region: case Column_Region:
{ {
return m_region_pixmaps[static_cast<int>(ge->region)]; return m_region_pixmaps[static_cast<u32>(ge->region)];
} }
case Column_Compatibility: case Column_Compatibility:
{ {
return m_compatibility_pixmaps[static_cast<int>( return m_compatibility_pixmaps[static_cast<u32>(
(static_cast<u32>(ge->compatibility_rating) >= GameList::CompatibilityRatingCount) ? (static_cast<u32>(ge->compatibility_rating) >= GameList::CompatibilityRatingCount) ?
GameList::CompatibilityRating::Unknown : GameList::CompatibilityRating::Unknown :
ge->compatibility_rating)]; ge->compatibility_rating)];
} }
@ -451,22 +440,38 @@ bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& r
} }
} }
QIcon GameListModel::getIconForType(GameList::EntryType type)
{
switch (type)
{
case GameList::EntryType::PS2Disc:
case GameList::EntryType::PS1Disc:
return QIcon(QStringLiteral(":/icons/media-optical-24.png"));
case GameList::EntryType::Playlist:
return QIcon(QStringLiteral(":/icons/address-book-new-22.png"));
case GameList::EntryType::ELF:
default:
return QIcon(QStringLiteral(":/icons/applications-system-24.png"));
}
}
QIcon GameListModel::getIconForRegion(GameList::Region region)
{
return QIcon(
QStringLiteral("%1/icons/flags/%2.png").arg(QtHost::GetResourcesBasePath()).arg(GameList::RegionToString(region)));
}
void GameListModel::loadCommonImages() void GameListModel::loadCommonImages()
{ {
m_type_disc_pixmap = QIcon(QStringLiteral(":/icons/media-optical-24.png")).pixmap(QSize(24, 24)); for (u32 type = 0; type < static_cast<u32>(GameList::EntryType::Count); type++)
m_type_disc_with_settings_pixmap = QIcon(QStringLiteral(":/icons/media-optical-gear-24.png")).pixmap(QSize(24, 24)); m_type_pixmaps[type] = getIconForType(static_cast<GameList::EntryType>(type)).pixmap(QSize(24, 24));
m_type_exe_pixmap = QIcon(QStringLiteral(":/icons/applications-system-24.png")).pixmap(QSize(24, 24));
m_type_playlist_pixmap = QIcon(QStringLiteral(":/icons/address-book-new-22.png")).pixmap(QSize(22, 22)); for (u32 i = 0; i < static_cast<u32>(GameList::Region::Count); i++)
m_region_pixmaps[i] = getIconForRegion(static_cast<GameList::Region>(i)).pixmap(QSize(42, 30));
const QString base_path(QtHost::GetResourcesBasePath()); const QString base_path(QtHost::GetResourcesBasePath());
for (u32 i = 0; i < static_cast<u32>(GameList::Region::Count); i++)
{
m_region_pixmaps[i] = QIcon(
QStringLiteral("%1/icons/flags/%2.png").arg(base_path).arg(GameList::RegionToString(static_cast<GameList::Region>(i))))
.pixmap(QSize(42, 30));
}
for (u32 i = 1; i < GameList::CompatibilityRatingCount; i++) for (u32 i = 1; i < GameList::CompatibilityRatingCount; i++)
m_compatibility_pixmaps[i].load(QStringLiteral("%1/icons/star-%2.png").arg(base_path).arg(i - 1)); m_compatibility_pixmaps[i].load(QStringLiteral("%1/icons/star-%2.png").arg(base_path).arg(i - 1));

View File

@ -45,6 +45,9 @@ public:
static std::optional<Column> getColumnIdForName(std::string_view name); static std::optional<Column> getColumnIdForName(std::string_view name);
static const char* getColumnName(Column col); static const char* getColumnName(Column col);
static QIcon getIconForType(GameList::EntryType type);
static QIcon getIconForRegion(GameList::Region region);
GameListModel(QObject* parent = nullptr); GameListModel(QObject* parent = nullptr);
~GameListModel(); ~GameListModel();
@ -79,12 +82,8 @@ private:
bool m_show_titles_for_covers = false; bool m_show_titles_for_covers = false;
std::array<QString, Column_Count> m_column_display_names; std::array<QString, Column_Count> m_column_display_names;
std::array<QPixmap, static_cast<u32>(GameList::EntryType::Count)> m_type_pixmaps;
QPixmap m_type_disc_pixmap; std::array<QPixmap, static_cast<u32>(GameList::Region::Count)> m_region_pixmaps;
QPixmap m_type_disc_with_settings_pixmap;
QPixmap m_type_exe_pixmap;
QPixmap m_type_playlist_pixmap;
QPixmap m_region_pixmaps[static_cast<u32>(GameList::Region::Count)];
QPixmap m_placeholder_pixmap; QPixmap m_placeholder_pixmap;
std::array<QPixmap, static_cast<int>(GameList::CompatibilityRatingCount)> m_compatibility_pixmaps; std::array<QPixmap, static_cast<int>(GameList::CompatibilityRatingCount)> m_compatibility_pixmaps;

View File

@ -40,6 +40,9 @@ static const char* SUPPORTED_FORMATS_STRING = QT_TRANSLATE_NOOP(GameListWidget,
".cso (Compressed ISO)\n" ".cso (Compressed ISO)\n"
".gz (Gzip Compressed ISO)"); ".gz (Gzip Compressed ISO)");
static constexpr float MIN_SCALE = 0.1f;
static constexpr float MAX_SCALE = 2.0f;
class GameListSortModel final : public QSortFilterProxyModel class GameListSortModel final : public QSortFilterProxyModel
{ {
public: public:
@ -49,9 +52,38 @@ public:
{ {
} }
void setFilterType(GameList::EntryType type)
{
m_filter_type = type;
invalidateRowsFilter();
}
void setFilterRegion(GameList::Region region)
{
m_filter_region = region;
invalidateRowsFilter();
}
void setFilterName(const QString& name)
{
m_filter_name = name;
invalidateRowsFilter();
}
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override
{ {
// TODO: Search if (m_filter_type != GameList::EntryType::Count ||
m_filter_region != GameList::Region::Count ||
!m_filter_name.isEmpty())
{
const auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryByIndex(source_row);
if (m_filter_type != GameList::EntryType::Count && entry->type != m_filter_type)
return false;
if (m_filter_region != GameList::Region::Count && entry->region != m_filter_region)
return false;
if (!m_filter_name.isEmpty() && !QString::fromStdString(entry->title).contains(m_filter_name, Qt::CaseInsensitive))
return false;
}
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
} }
@ -62,10 +94,13 @@ public:
private: private:
GameListModel* m_model; GameListModel* m_model;
GameList::EntryType m_filter_type = GameList::EntryType::Count;
GameList::Region m_filter_region = GameList::Region::Count;
QString m_filter_name;
}; };
GameListWidget::GameListWidget(QWidget* parent /* = nullptr */) GameListWidget::GameListWidget(QWidget* parent /* = nullptr */)
: QStackedWidget(parent) : QWidget(parent)
{ {
} }
@ -79,7 +114,34 @@ void GameListWidget::initialize()
m_sort_model = new GameListSortModel(m_model); m_sort_model = new GameListSortModel(m_model);
m_sort_model->setSourceModel(m_model); m_sort_model->setSourceModel(m_model);
m_table_view = new QTableView(this);
m_ui.setupUi(this);
for (u32 type = 0; type < static_cast<u32>(GameList::EntryType::Count); type++)
{
m_ui.filterType->addItem(GameListModel::getIconForType(static_cast<GameList::EntryType>(type)),
qApp->translate("GameList", GameList::EntryTypeToDisplayString(static_cast<GameList::EntryType>(type))));
}
for (u32 region = 0; region < static_cast<u32>(GameList::Region::Count); region++)
{
m_ui.filterRegion->addItem(GameListModel::getIconForRegion(static_cast<GameList::Region>(region)),
qApp->translate("GameList", GameList::RegionToString(static_cast<GameList::Region>(region))));
}
connect(m_ui.viewGameList, &QPushButton::clicked, this, &GameListWidget::showGameList);
connect(m_ui.viewGameGrid, &QPushButton::clicked, this, &GameListWidget::showGameGrid);
connect(m_ui.gridScale, &QSlider::valueChanged, this, &GameListWidget::gridIntScale);
connect(m_ui.viewGridTitles, &QPushButton::toggled, this, &GameListWidget::setShowCoverTitles);
connect(m_ui.filterType, &QComboBox::currentIndexChanged, this, [this](int index) {
m_sort_model->setFilterType((index == 0) ? GameList::EntryType::Count : static_cast<GameList::EntryType>(index - 1));
});
connect(m_ui.filterRegion, &QComboBox::currentIndexChanged, this, [this](int index) {
m_sort_model->setFilterRegion((index == 0) ? GameList::Region::Count : static_cast<GameList::Region>(index - 1));
});
connect(m_ui.searchText, &QLineEdit::textChanged, this, [this](const QString& text) {
m_sort_model->setFilterName(text);
});
m_table_view = new QTableView(m_ui.stack);
m_table_view->setModel(m_sort_model); m_table_view->setModel(m_sort_model);
m_table_view->setSortingEnabled(true); m_table_view->setSortingEnabled(true);
m_table_view->setSelectionMode(QAbstractItemView::SingleSelection); m_table_view->setSelectionMode(QAbstractItemView::SingleSelection);
@ -107,9 +169,9 @@ void GameListWidget::initialize()
connect(m_table_view->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this, connect(m_table_view->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this,
&GameListWidget::onTableViewHeaderSortIndicatorChanged); &GameListWidget::onTableViewHeaderSortIndicatorChanged);
insertWidget(0, m_table_view); m_ui.stack->insertWidget(0, m_table_view);
m_list_view = new GameListGridListView(this); m_list_view = new GameListGridListView(m_ui.stack);
m_list_view->setModel(m_sort_model); m_list_view->setModel(m_sort_model);
m_list_view->setModelColumn(GameListModel::Column_Cover); m_list_view->setModelColumn(GameListModel::Column_Cover);
m_list_view->setSelectionMode(QAbstractItemView::ExtendedSelection); m_list_view->setSelectionMode(QAbstractItemView::ExtendedSelection);
@ -131,31 +193,32 @@ void GameListWidget::initialize()
connect(m_list_view, &QListView::activated, this, &GameListWidget::onListViewItemActivated); connect(m_list_view, &QListView::activated, this, &GameListWidget::onListViewItemActivated);
connect(m_list_view, &QListView::customContextMenuRequested, this, &GameListWidget::onListViewContextMenuRequested); connect(m_list_view, &QListView::customContextMenuRequested, this, &GameListWidget::onListViewContextMenuRequested);
insertWidget(1, m_list_view); m_ui.stack->insertWidget(1, m_list_view);
m_empty_widget = new QWidget(this); m_empty_widget = new QWidget(m_ui.stack);
m_empty_ui.setupUi(m_empty_widget); m_empty_ui.setupUi(m_empty_widget);
m_empty_ui.supportedFormats->setText(qApp->translate("GameListWidget", SUPPORTED_FORMATS_STRING)); m_empty_ui.supportedFormats->setText(qApp->translate("GameListWidget", SUPPORTED_FORMATS_STRING));
connect(m_empty_ui.addGameDirectory, &QPushButton::clicked, this, [this]() { emit addGameDirectoryRequested(); }); connect(m_empty_ui.addGameDirectory, &QPushButton::clicked, this, [this]() { emit addGameDirectoryRequested(); });
connect(m_empty_ui.scanForNewGames, &QPushButton::clicked, this, [this]() { refresh(false); }); connect(m_empty_ui.scanForNewGames, &QPushButton::clicked, this, [this]() { refresh(false); });
insertWidget(2, m_empty_widget); m_ui.stack->insertWidget(2, m_empty_widget);
if (Host::GetBaseBoolSettingValue("UI", "GameListGridView", false)) if (Host::GetBaseBoolSettingValue("UI", "GameListGridView", false))
setCurrentIndex(1); m_ui.stack->setCurrentIndex(1);
else else
setCurrentIndex(0); m_ui.stack->setCurrentIndex(0);
updateToolbar();
resizeTableViewColumnsToFit(); resizeTableViewColumnsToFit();
} }
bool GameListWidget::isShowingGameList() const bool GameListWidget::isShowingGameList() const
{ {
return currentIndex() == 0; return m_ui.stack->currentIndex() == 0;
} }
bool GameListWidget::isShowingGameGrid() const bool GameListWidget::isShowingGameGrid() const
{ {
return currentIndex() == 1; return m_ui.stack->currentIndex() == 1;
} }
bool GameListWidget::getShowGridCoverTitles() const bool GameListWidget::getShowGridCoverTitles() const
@ -189,8 +252,8 @@ void GameListWidget::cancelRefresh()
void GameListWidget::onRefreshProgress(const QString& status, int current, int total) void GameListWidget::onRefreshProgress(const QString& status, int current, int total)
{ {
// switch away from the placeholder while we scan, in case we find anything // switch away from the placeholder while we scan, in case we find anything
if (currentIndex() == 2) if (m_ui.stack->currentIndex() == 2)
setCurrentIndex(Host::GetBaseBoolSettingValue("UI", "GameListGridView", false) ? 1 : 0); m_ui.stack->setCurrentIndex(Host::GetBaseBoolSettingValue("UI", "GameListGridView", false) ? 1 : 0);
m_model->refresh(); m_model->refresh();
emit refreshProgress(status, current, total); emit refreshProgress(status, current, total);
@ -208,7 +271,7 @@ void GameListWidget::onRefreshComplete()
// if we still had no games, switch to the helper widget // if we still had no games, switch to the helper widget
if (m_model->rowCount() == 0) if (m_model->rowCount() == 0)
setCurrentIndex(2); m_ui.stack->setCurrentIndex(2);
} }
void GameListWidget::onSelectionModelCurrentChanged(const QModelIndex& current, const QModelIndex& previous) void GameListWidget::onSelectionModelCurrentChanged(const QModelIndex& current, const QModelIndex& previous)
@ -277,13 +340,11 @@ void GameListWidget::onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder)
void GameListWidget::listZoom(float delta) void GameListWidget::listZoom(float delta)
{ {
static constexpr float MIN_SCALE = 0.1f;
static constexpr float MAX_SCALE = 2.0f;
const float new_scale = std::clamp(m_model->getCoverScale() + delta, MIN_SCALE, MAX_SCALE); const float new_scale = std::clamp(m_model->getCoverScale() + delta, MIN_SCALE, MAX_SCALE);
QtHost::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale); QtHost::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
m_model->setCoverScale(new_scale); m_model->setCoverScale(new_scale);
updateListFont(); updateListFont();
updateToolbar();
m_model->refresh(); m_model->refresh();
} }
@ -298,6 +359,18 @@ void GameListWidget::gridZoomOut()
listZoom(-0.05f); listZoom(-0.05f);
} }
void GameListWidget::gridIntScale(int int_scale)
{
const float new_scale = std::clamp(static_cast<float>(int_scale) / 100.0f, MIN_SCALE, MAX_SCALE);
QtHost::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
m_model->setCoverScale(new_scale);
updateListFont();
updateToolbar();
m_model->refresh();
}
void GameListWidget::refreshGridCovers() void GameListWidget::refreshGridCovers()
{ {
m_model->refreshCovers(); m_model->refreshCovers();
@ -305,21 +378,33 @@ void GameListWidget::refreshGridCovers()
void GameListWidget::showGameList() void GameListWidget::showGameList()
{ {
if (currentIndex() == 0 || m_model->rowCount() == 0) if (m_ui.stack->currentIndex() == 0 || m_model->rowCount() == 0)
{
// We can click the toolbar multiple times, so keep it correct.
updateToolbar();
return; return;
}
QtHost::SetBaseBoolSettingValue("UI", "GameListGridView", false); QtHost::SetBaseBoolSettingValue("UI", "GameListGridView", false);
setCurrentIndex(0); m_ui.stack->setCurrentIndex(0);
resizeTableViewColumnsToFit(); resizeTableViewColumnsToFit();
updateToolbar();
emit layoutChange();
} }
void GameListWidget::showGameGrid() void GameListWidget::showGameGrid()
{ {
if (currentIndex() == 1 || m_model->rowCount() == 0) if (m_ui.stack->currentIndex() == 1 || m_model->rowCount() == 0)
{
// We can click the toolbar multiple times, so keep it correct.
updateToolbar();
return; return;
}
QtHost::SetBaseBoolSettingValue("UI", "GameListGridView", true); QtHost::SetBaseBoolSettingValue("UI", "GameListGridView", true);
setCurrentIndex(1); m_ui.stack->setCurrentIndex(1);
updateToolbar();
emit layoutChange();
} }
void GameListWidget::setShowCoverTitles(bool enabled) void GameListWidget::setShowCoverTitles(bool enabled)
@ -331,6 +416,8 @@ void GameListWidget::setShowCoverTitles(bool enabled)
m_model->setShowCoverTitles(enabled); m_model->setShowCoverTitles(enabled);
if (isShowingGameGrid()) if (isShowingGameGrid())
m_model->refresh(); m_model->refresh();
updateToolbar();
emit layoutChange();
} }
void GameListWidget::updateListFont() void GameListWidget::updateListFont()
@ -340,9 +427,33 @@ void GameListWidget::updateListFont()
m_list_view->setFont(font); m_list_view->setFont(font);
} }
void GameListWidget::updateToolbar()
{
const bool grid_view = isShowingGameGrid();
{
QSignalBlocker sb(m_ui.viewGameGrid);
m_ui.viewGameGrid->setChecked(grid_view);
}
{
QSignalBlocker sb(m_ui.viewGameList);
m_ui.viewGameList->setChecked(!grid_view);
}
{
QSignalBlocker sb(m_ui.viewGridTitles);
m_ui.viewGridTitles->setChecked(m_model->getShowCoverTitles());
}
{
QSignalBlocker sb(m_ui.gridScale);
m_ui.gridScale->setValue(static_cast<int>(m_model->getCoverScale() * 100.0f));
}
m_ui.viewGridTitles->setEnabled(grid_view);
m_ui.gridScale->setEnabled(grid_view);
}
void GameListWidget::resizeEvent(QResizeEvent* event) void GameListWidget::resizeEvent(QResizeEvent* event)
{ {
QStackedWidget::resizeEvent(event); QWidget::resizeEvent(event);
resizeTableViewColumnsToFit(); resizeTableViewColumnsToFit();
} }
@ -431,7 +542,7 @@ void GameListWidget::saveTableViewColumnSortSettings()
const GameList::Entry* GameListWidget::getSelectedEntry() const const GameList::Entry* GameListWidget::getSelectedEntry() const
{ {
if (currentIndex() == 0) if (m_ui.stack->currentIndex() == 0)
{ {
const QItemSelectionModel* selection_model = m_table_view->selectionModel(); const QItemSelectionModel* selection_model = m_table_view->selectionModel();
if (!selection_model->hasSelection()) if (!selection_model->hasSelection())

View File

@ -16,8 +16,8 @@
#pragma once #pragma once
#include "pcsx2/Frontend/GameList.h" #include "pcsx2/Frontend/GameList.h"
#include "ui_EmptyGameListWidget.h" #include "ui_EmptyGameListWidget.h"
#include "ui_GameListWidget.h"
#include <QtWidgets/QListView> #include <QtWidgets/QListView>
#include <QtWidgets/QStackedWidget>
#include <QtWidgets/QTableView> #include <QtWidgets/QTableView>
Q_DECLARE_METATYPE(const GameList::Entry*); Q_DECLARE_METATYPE(const GameList::Entry*);
@ -41,7 +41,7 @@ protected:
void wheelEvent(QWheelEvent* e); void wheelEvent(QWheelEvent* e);
}; };
class GameListWidget : public QStackedWidget class GameListWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
@ -59,7 +59,6 @@ public:
bool isShowingGameList() const; bool isShowingGameList() const;
bool isShowingGameGrid() const; bool isShowingGameGrid() const;
bool getShowGridCoverTitles() const; bool getShowGridCoverTitles() const;
const GameList::Entry* getSelectedEntry() const; const GameList::Entry* getSelectedEntry() const;
@ -73,6 +72,7 @@ Q_SIGNALS:
void entryContextMenuRequested(const QPoint& point); void entryContextMenuRequested(const QPoint& point);
void addGameDirectoryRequested(); void addGameDirectoryRequested();
void layoutChange();
private Q_SLOTS: private Q_SLOTS:
void onRefreshProgress(const QString& status, int current, int total); void onRefreshProgress(const QString& status, int current, int total);
@ -92,6 +92,7 @@ public Q_SLOTS:
void setShowCoverTitles(bool enabled); void setShowCoverTitles(bool enabled);
void gridZoomIn(); void gridZoomIn();
void gridZoomOut(); void gridZoomOut();
void gridIntScale(int int_scale);
void refreshGridCovers(); void refreshGridCovers();
protected: protected:
@ -105,6 +106,9 @@ private:
void saveTableViewColumnSortSettings(); void saveTableViewColumnSortSettings();
void listZoom(float delta); void listZoom(float delta);
void updateListFont(); void updateListFont();
void updateToolbar();
Ui::GameListWidget m_ui;
GameListModel* m_model = nullptr; GameListModel* m_model = nullptr;
GameListSortModel* m_sort_model = nullptr; GameListSortModel* m_sort_model = nullptr;

View File

@ -0,0 +1,220 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GameListWidget</class>
<widget class="QWidget" name="GameListWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>758</width>
<height>619</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>3</number>
</property>
<item>
<widget class="QToolButton" name="viewGameList">
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Game List</string>
</property>
<property name="icon">
<iconset theme="list-check">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="viewGameGrid">
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Game Grid</string>
</property>
<property name="icon">
<iconset theme="function-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="viewGridTitles">
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Show Titles</string>
</property>
<property name="icon">
<iconset theme="price-tag-3-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="gridScale">
<property name="minimumSize">
<size>
<width>125</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>16777215</height>
</size>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QComboBox" name="filterType">
<item>
<property name="text">
<string>All Types</string>
</property>
<property name="icon">
<iconset theme="filter-line">
<normaloff>.</normaloff>.</iconset>
</property>
</item>
</widget>
</item>
<item>
<widget class="QComboBox" name="filterRegion">
<item>
<property name="text">
<string>All Regions</string>
</property>
<property name="icon">
<iconset theme="global-line">
<normaloff>.</normaloff>.</iconset>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLineEdit" name="searchText">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="placeholderText">
<string>Search...</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="stack"/>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -300,6 +300,10 @@ void MainWindow::connectSignals()
m_game_list_widget->gridZoomOut(); m_game_list_widget->gridZoomOut();
}); });
connect(m_ui.actionGridViewRefreshCovers, &QAction::triggered, m_game_list_widget, &GameListWidget::refreshGridCovers); connect(m_ui.actionGridViewRefreshCovers, &QAction::triggered, m_game_list_widget, &GameListWidget::refreshGridCovers);
connect(m_game_list_widget, &GameListWidget::layoutChange, this, [this]() {
QSignalBlocker sb(m_ui.actionGridViewShowTitles);
m_ui.actionGridViewShowTitles->setChecked(m_game_list_widget->getShowGridCoverTitles());
});
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionViewStatusBarVerbose, "UI", "VerboseStatusBar", false); SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionViewStatusBarVerbose, "UI", "VerboseStatusBar", false);
@ -534,6 +538,7 @@ void MainWindow::setStyleFromSettings()
darkPalette.setColor(QPalette::Link, blue); darkPalette.setColor(QPalette::Link, blue);
darkPalette.setColor(QPalette::Highlight, lighterGray); darkPalette.setColor(QPalette::Highlight, lighterGray);
darkPalette.setColor(QPalette::HighlightedText, Qt::white); darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
darkPalette.setColor(QPalette::Active, QPalette::Button, gray.darker()); darkPalette.setColor(QPalette::Active, QPalette::Button, gray.darker());
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray); darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
@ -569,6 +574,7 @@ void MainWindow::setStyleFromSettings()
darkPalette.setColor(QPalette::Link, blue); darkPalette.setColor(QPalette::Link, blue);
darkPalette.setColor(QPalette::Highlight, blue2); darkPalette.setColor(QPalette::Highlight, blue2);
darkPalette.setColor(QPalette::HighlightedText, Qt::white); darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
darkPalette.setColor(QPalette::Active, QPalette::Button, gray.darker()); darkPalette.setColor(QPalette::Active, QPalette::Button, gray.darker());
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray); darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);

View File

@ -265,6 +265,9 @@
<QtUi Include="GameList\EmptyGameListWidget.ui"> <QtUi Include="GameList\EmptyGameListWidget.ui">
<FileType>Document</FileType> <FileType>Document</FileType>
</QtUi> </QtUi>
<QtUi Include="GameList\GameListWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\SettingsDialog.ui"> <QtUi Include="Settings\SettingsDialog.ui">
<FileType>Document</FileType> <FileType>Document</FileType>
</QtUi> </QtUi>

View File

@ -399,6 +399,9 @@
<QtUi Include="GameList\EmptyGameListWidget.ui"> <QtUi Include="GameList\EmptyGameListWidget.ui">
<Filter>GameList</Filter> <Filter>GameList</Filter>
</QtUi> </QtUi>
<QtUi Include="GameList\GameListWidget.ui">
<Filter>GameList</Filter>
</QtUi>
<QtUi Include="AutoUpdaterDialog.ui" /> <QtUi Include="AutoUpdaterDialog.ui" />
<QtUi Include="Tools\InputRecording\NewInputRecordingDlg.ui"> <QtUi Include="Tools\InputRecording\NewInputRecordingDlg.ui">
<Filter>Tools\Input Recording</Filter> <Filter>Tools\Input Recording</Filter>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0H24V24H0z"/><path d="M21 4v2h-1l-5 7.5V22H9v-8.5L4 6H3V4h18zM6.404 6L11 12.894V20h2v-7.106L17.596 6H6.404z" fill="#000000"/></svg>

After

Width:  |  Height:  |  Size: 238 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-2.29-2.333A17.9 17.9 0 0 1 8.027 13H4.062a8.008 8.008 0 0 0 5.648 6.667zM10.03 13c.151 2.439.848 4.73 1.97 6.752A15.905 15.905 0 0 0 13.97 13h-3.94zm9.908 0h-3.965a17.9 17.9 0 0 1-1.683 6.667A8.008 8.008 0 0 0 19.938 13zM4.062 11h3.965A17.9 17.9 0 0 1 9.71 4.333 8.008 8.008 0 0 0 4.062 11zm5.969 0h3.938A15.905 15.905 0 0 0 12 4.248 15.905 15.905 0 0 0 10.03 11zm4.259-6.667A17.9 17.9 0 0 1 15.973 11h3.965a8.008 8.008 0 0 0-5.648-6.667z" fill="#000000"/></svg>

After

Width:  |  Height:  |  Size: 666 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10.9 2.1l9.899 1.415 1.414 9.9-9.192 9.192a1 1 0 0 1-1.414 0l-9.9-9.9a1 1 0 0 1 0-1.414L10.9 2.1zm.707 2.122L3.828 12l8.486 8.485 7.778-7.778-1.06-7.425-7.425-1.06zm2.12 6.364a2 2 0 1 1 2.83-2.829 2 2 0 0 1-2.83 2.829z" fill="#000000"/></svg>

After

Width:  |  Height:  |  Size: 372 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0H24V24H0z"/><path d="M21 4v2h-1l-5 7.5V22H9v-8.5L4 6H3V4h18zM6.404 6L11 12.894V20h2v-7.106L17.596 6H6.404z" fill="#ffffff"/></svg>

After

Width:  |  Height:  |  Size: 238 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-2.29-2.333A17.9 17.9 0 0 1 8.027 13H4.062a8.008 8.008 0 0 0 5.648 6.667zM10.03 13c.151 2.439.848 4.73 1.97 6.752A15.905 15.905 0 0 0 13.97 13h-3.94zm9.908 0h-3.965a17.9 17.9 0 0 1-1.683 6.667A8.008 8.008 0 0 0 19.938 13zM4.062 11h3.965A17.9 17.9 0 0 1 9.71 4.333 8.008 8.008 0 0 0 4.062 11zm5.969 0h3.938A15.905 15.905 0 0 0 12 4.248 15.905 15.905 0 0 0 10.03 11zm4.259-6.667A17.9 17.9 0 0 1 15.973 11h3.965a8.008 8.008 0 0 0-5.648-6.667z" fill="#ffffff"/></svg>

After

Width:  |  Height:  |  Size: 666 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10.9 2.1l9.899 1.415 1.414 9.9-9.192 9.192a1 1 0 0 1-1.414 0l-9.9-9.9a1 1 0 0 1 0-1.414L10.9 2.1zm.707 2.122L3.828 12l8.486 8.485 7.778-7.778-1.06-7.425-7.425-1.06zm2.12 6.364a2 2 0 1 1 2.83-2.829 2 2 0 0 1-2.83 2.829z" fill="#ffffff"/></svg>

After

Width:  |  Height:  |  Size: 372 B

View File

@ -20,6 +20,7 @@
<file>icons/black/svg/file-reduce-line.svg</file> <file>icons/black/svg/file-reduce-line.svg</file>
<file>icons/black/svg/file-search-line.svg</file> <file>icons/black/svg/file-search-line.svg</file>
<file>icons/black/svg/file-settings-line.svg</file> <file>icons/black/svg/file-settings-line.svg</file>
<file>icons/black/svg/filter-line.svg</file>
<file>icons/black/svg/flask-line.svg</file> <file>icons/black/svg/flask-line.svg</file>
<file>icons/black/svg/folder-add-line.svg</file> <file>icons/black/svg/folder-add-line.svg</file>
<file>icons/black/svg/folder-open-line.svg</file> <file>icons/black/svg/folder-open-line.svg</file>
@ -28,12 +29,14 @@
<file>icons/black/svg/fullscreen-line.svg</file> <file>icons/black/svg/fullscreen-line.svg</file>
<file>icons/black/svg/function-line.svg</file> <file>icons/black/svg/function-line.svg</file>
<file>icons/black/svg/gamepad-line.svg</file> <file>icons/black/svg/gamepad-line.svg</file>
<file>icons/black/svg/global-line.svg</file>
<file>icons/black/svg/hard-drive-2-line.svg</file> <file>icons/black/svg/hard-drive-2-line.svg</file>
<file>icons/black/svg/keyboard-line.svg</file> <file>icons/black/svg/keyboard-line.svg</file>
<file>icons/black/svg/layout-grid-line.svg</file> <file>icons/black/svg/layout-grid-line.svg</file>
<file>icons/black/svg/list-check.svg</file> <file>icons/black/svg/list-check.svg</file>
<file>icons/black/svg/pause-line.svg</file> <file>icons/black/svg/pause-line.svg</file>
<file>icons/black/svg/play-line.svg</file> <file>icons/black/svg/play-line.svg</file>
<file>icons/black/svg/price-tag-3-line.svg</file>
<file>icons/black/svg/refresh-line.svg</file> <file>icons/black/svg/refresh-line.svg</file>
<file>icons/black/svg/restart-line.svg</file> <file>icons/black/svg/restart-line.svg</file>
<file>icons/black/svg/save-3-line.svg</file> <file>icons/black/svg/save-3-line.svg</file>
@ -69,6 +72,7 @@
<file>icons/white/svg/file-reduce-line.svg</file> <file>icons/white/svg/file-reduce-line.svg</file>
<file>icons/white/svg/file-search-line.svg</file> <file>icons/white/svg/file-search-line.svg</file>
<file>icons/white/svg/file-settings-line.svg</file> <file>icons/white/svg/file-settings-line.svg</file>
<file>icons/white/svg/filter-line.svg</file>
<file>icons/white/svg/flask-line.svg</file> <file>icons/white/svg/flask-line.svg</file>
<file>icons/white/svg/folder-add-line.svg</file> <file>icons/white/svg/folder-add-line.svg</file>
<file>icons/white/svg/folder-open-line.svg</file> <file>icons/white/svg/folder-open-line.svg</file>
@ -77,12 +81,14 @@
<file>icons/white/svg/fullscreen-line.svg</file> <file>icons/white/svg/fullscreen-line.svg</file>
<file>icons/white/svg/function-line.svg</file> <file>icons/white/svg/function-line.svg</file>
<file>icons/white/svg/gamepad-line.svg</file> <file>icons/white/svg/gamepad-line.svg</file>
<file>icons/white/svg/global-line.svg</file>
<file>icons/white/svg/hard-drive-2-line.svg</file> <file>icons/white/svg/hard-drive-2-line.svg</file>
<file>icons/white/svg/keyboard-line.svg</file> <file>icons/white/svg/keyboard-line.svg</file>
<file>icons/white/svg/layout-grid-line.svg</file> <file>icons/white/svg/layout-grid-line.svg</file>
<file>icons/white/svg/list-check.svg</file> <file>icons/white/svg/list-check.svg</file>
<file>icons/white/svg/pause-line.svg</file> <file>icons/white/svg/pause-line.svg</file>
<file>icons/white/svg/play-line.svg</file> <file>icons/white/svg/play-line.svg</file>
<file>icons/white/svg/price-tag-3-line.svg</file>
<file>icons/white/svg/refresh-line.svg</file> <file>icons/white/svg/refresh-line.svg</file>
<file>icons/white/svg/restart-line.svg</file> <file>icons/white/svg/restart-line.svg</file>
<file>icons/white/svg/save-3-line.svg</file> <file>icons/white/svg/save-3-line.svg</file>

View File

@ -86,6 +86,12 @@ const char* GameList::EntryTypeToString(EntryType type)
return names[static_cast<int>(type)]; return names[static_cast<int>(type)];
} }
const char* GameList::EntryTypeToDisplayString(EntryType type)
{
static std::array<const char*, static_cast<int>(EntryType::Count)> names = {{"PS2 Disc", "PS1 Disc", "ELF", "Playlist"}};
return names[static_cast<int>(type)];
}
const char* GameList::RegionToString(Region region) const char* GameList::RegionToString(Region region)
{ {
static std::array<const char*, static_cast<int>(Region::Count)> names = { static std::array<const char*, static_cast<int>(Region::Count)> names = {

View File

@ -96,6 +96,7 @@ namespace GameList
}; };
const char* EntryTypeToString(EntryType type); const char* EntryTypeToString(EntryType type);
const char* EntryTypeToDisplayString(EntryType type);
const char* RegionToString(Region region); const char* RegionToString(Region region);
const char* EntryCompatibilityRatingToString(CompatibilityRating rating); const char* EntryCompatibilityRatingToString(CompatibilityRating rating);