Qt: Move list/grid setup to subclasses

This commit is contained in:
Stenzek 2025-06-05 19:06:00 +10:00
parent 808c51b3ce
commit 95e085584c
No known key found for this signature in database
3 changed files with 320 additions and 312 deletions

View File

@ -120,14 +120,16 @@ const char* GameListModel::getColumnName(Column col)
return s_column_names[static_cast<int>(col)];
}
GameListModel::GameListModel(float cover_scale, bool show_cover_titles, bool show_game_icons,
QObject* parent /* = nullptr */)
: QAbstractTableModel(parent), m_show_titles_for_covers(show_cover_titles), m_show_game_icons(show_game_icons),
m_memcard_pixmap_cache(MIN_COVER_CACHE_SIZE)
GameListModel::GameListModel(QObject* parent)
: QAbstractTableModel(parent), m_memcard_pixmap_cache(MIN_COVER_CACHE_SIZE)
{
m_cover_scale = Host::GetBaseFloatSettingValue("UI", "GameListCoverArtScale", 0.45f);
m_show_titles_for_covers = Host::GetBaseBoolSettingValue("UI", "GameListShowCoverTitles", true);
m_show_game_icons = Host::GetBaseBoolSettingValue("UI", "GameListShowGameIcons", true);
loadCommonImages();
setCoverScale(cover_scale);
setColumnDisplayNames();
updateCoverScale();
if (m_show_game_icons)
GameList::ReloadMemcardTimestampCache();
@ -153,9 +155,17 @@ void GameListModel::setCoverScale(float scale)
if (m_cover_scale == scale)
return;
m_cover_pixmap_cache.Clear();
m_cover_scale = scale;
Host::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", scale);
Host::CommitBaseSettingChanges();
updateCoverScale();
}
void GameListModel::updateCoverScale()
{
m_cover_pixmap_cache.Clear();
const qreal dpr = qApp->devicePixelRatio();
QImage loading_image;
@ -185,7 +195,8 @@ void GameListModel::setCoverScale(float scale)
m_placeholder_image.fill(QColor(0, 0, 0, 0));
}
emit coverScaleChanged();
emit coverScaleChanged(m_cover_scale);
refresh();
}
void GameListModel::refreshCovers()
@ -1111,25 +1122,6 @@ private:
GameListSortModel* m_sort_model;
};
class GameListGridDelegate : public QStyledItemDelegate
{
public:
GameListGridDelegate(bool show_titles) : m_show_titles(show_titles) {}
protected:
void initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const override
{
QStyledItemDelegate::initStyleOption(option, index);
if (!m_show_titles)
option->features &= ~QStyleOptionViewItem::HasDisplay;
// else
// option->features |= QStyleOptionViewItem::WrapText;
}
private:
bool m_show_titles = false;
};
} // namespace
GameListWidget::GameListWidget(QWidget* parent /* = nullptr */) : QWidget(parent)
@ -1140,11 +1132,10 @@ GameListWidget::~GameListWidget() = default;
void GameListWidget::initialize()
{
const float cover_scale = Host::GetBaseFloatSettingValue("UI", "GameListCoverArtScale", 0.45f);
const bool show_cover_titles = Host::GetBaseBoolSettingValue("UI", "GameListShowCoverTitles", true);
const bool merge_disc_sets = Host::GetBaseBoolSettingValue("UI", "GameListMergeDiscSets", true);
const bool show_game_icons = Host::GetBaseBoolSettingValue("UI", "GameListShowGameIcons", true);
m_model = new GameListModel(cover_scale, show_cover_titles, show_game_icons, this);
m_model = new GameListModel(this);
connect(m_model, &GameListModel::coverScaleChanged, this, &GameListWidget::onCoverScaleChanged);
m_sort_model = new GameListSortModel(m_model);
m_sort_model->setSourceModel(m_model);
@ -1163,9 +1154,20 @@ void GameListWidget::initialize()
QString::fromUtf8(Settings::GetDiscRegionName(static_cast<DiscRegion>(region))));
}
m_list_view = new GameListListView(m_model, m_sort_model, m_ui.stack);
m_ui.stack->insertWidget(0, m_list_view);
m_grid_view = new GameListGridView(m_model, m_sort_model, m_ui.stack);
m_ui.stack->insertWidget(1, m_grid_view);
m_empty_widget = new QWidget(m_ui.stack);
m_empty_ui.setupUi(m_empty_widget);
m_empty_ui.supportedFormats->setText(qApp->translate("GameListWidget", SUPPORTED_FORMATS_STRING));
m_ui.stack->insertWidget(2, m_empty_widget);
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.gridScale, &QSlider::valueChanged, m_grid_view, &GameListGridView::setZoomPct);
connect(m_ui.viewGridTitles, &QPushButton::toggled, this, &GameListWidget::setShowCoverTitles);
connect(m_ui.viewMergeDiscSets, &QPushButton::toggled, this, &GameListWidget::setMergeDiscSets);
connect(m_ui.filterType, &QComboBox::currentIndexChanged, this, [this](int index) {
@ -1179,72 +1181,18 @@ void GameListWidget::initialize()
[this](const QString& text) { m_sort_model->setFilterName(text.toStdString()); });
connect(m_ui.searchText, &QLineEdit::returnPressed, this, &GameListWidget::onSearchReturnPressed);
GameListCenterIconStyleDelegate* center_icon_delegate = new GameListCenterIconStyleDelegate(this);
m_list_view = new QTableView(m_ui.stack);
m_list_view->setModel(m_sort_model);
m_list_view->setSortingEnabled(true);
m_list_view->setSelectionMode(QAbstractItemView::SingleSelection);
m_list_view->setSelectionBehavior(QAbstractItemView::SelectRows);
m_list_view->setContextMenuPolicy(Qt::CustomContextMenu);
m_list_view->setAlternatingRowColors(true);
m_list_view->setShowGrid(false);
m_list_view->setCurrentIndex({});
m_list_view->horizontalHeader()->setHighlightSections(false);
m_list_view->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
m_list_view->verticalHeader()->hide();
m_list_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_list_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
m_list_view->setItemDelegateForColumn(GameListModel::Column_Icon, center_icon_delegate);
m_list_view->setItemDelegateForColumn(GameListModel::Column_Region, center_icon_delegate);
m_list_view->setItemDelegateForColumn(GameListModel::Column_Achievements,
new GameListAchievementsStyleDelegate(this, m_model, m_sort_model));
loadTableViewColumnVisibilitySettings();
loadTableViewColumnSortSettings();
connect(m_list_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
&GameListWidget::onSelectionModelCurrentChanged);
connect(m_list_view, &QTableView::activated, this, &GameListWidget::onTableViewItemActivated);
connect(m_list_view, &QTableView::customContextMenuRequested, this, &GameListWidget::onTableViewContextMenuRequested);
connect(m_list_view->horizontalHeader(), &QHeaderView::customContextMenuRequested, this,
&GameListWidget::onTableViewHeaderContextMenuRequested);
connect(m_list_view->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this,
&GameListWidget::onTableViewHeaderSortIndicatorChanged);
m_ui.stack->insertWidget(0, m_list_view);
m_grid_view = new GameListGridListView(m_model, m_ui.stack);
m_grid_view->setModel(m_sort_model);
m_grid_view->setModelColumn(GameListModel::Column_Cover);
m_grid_view->setSelectionMode(QAbstractItemView::SingleSelection);
m_grid_view->setViewMode(QListView::IconMode);
m_grid_view->setResizeMode(QListView::Adjust);
m_grid_view->setUniformItemSizes(true);
m_grid_view->setItemAlignment(Qt::AlignHCenter);
m_grid_view->setContextMenuPolicy(Qt::CustomContextMenu);
m_grid_view->setFrameStyle(QFrame::NoFrame);
m_grid_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
m_grid_view->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_grid_view->verticalScrollBar()->setSingleStep(15);
onCoverScaleChanged();
connect(m_list_view, &QTableView::activated, this, &GameListWidget::onListViewItemActivated);
connect(m_list_view, &QTableView::customContextMenuRequested, this, &GameListWidget::onListViewContextMenuRequested);
connect(m_grid_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
&GameListWidget::onSelectionModelCurrentChanged);
connect(m_grid_view, &GameListGridListView::zoomIn, this, &GameListWidget::gridZoomIn);
connect(m_grid_view, &GameListGridListView::zoomOut, this, &GameListWidget::gridZoomOut);
connect(m_grid_view, &QListView::activated, this, &GameListWidget::onListViewItemActivated);
connect(m_grid_view, &QListView::customContextMenuRequested, this, &GameListWidget::onListViewContextMenuRequested);
connect(m_model, &GameListModel::coverScaleChanged, this, &GameListWidget::onCoverScaleChanged);
connect(m_grid_view, &QListView::activated, this, &GameListWidget::onGridViewItemActivated);
connect(m_grid_view, &QListView::customContextMenuRequested, this, &GameListWidget::onGridViewContextMenuRequested);
m_ui.stack->insertWidget(1, m_grid_view);
m_empty_widget = new QWidget(m_ui.stack);
m_empty_ui.setupUi(m_empty_widget);
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.scanForNewGames, &QPushButton::clicked, this, [this]() { refresh(false); });
m_ui.stack->insertWidget(2, m_empty_widget);
const bool grid_view = Host::GetBaseBoolSettingValue("UI", "GameListGridView", false);
if (grid_view)
@ -1254,7 +1202,7 @@ void GameListWidget::initialize()
setFocusProxy(grid_view ? static_cast<QWidget*>(m_grid_view) : static_cast<QWidget*>(m_list_view));
updateToolbar();
resizeTableViewColumnsToFit();
resizeListViewColumnsToFit();
updateBackground(true);
}
@ -1401,7 +1349,7 @@ void GameListWidget::onSelectionModelCurrentChanged(const QModelIndex& current,
emit selectionChanged();
}
void GameListWidget::onTableViewItemActivated(const QModelIndex& index)
void GameListWidget::onListViewItemActivated(const QModelIndex& index)
{
const QModelIndex source_index = m_sort_model->mapToSource(index);
if (!source_index.isValid() || source_index.row() >= static_cast<int>(GameList::GetEntryCount()))
@ -1420,12 +1368,12 @@ void GameListWidget::onTableViewItemActivated(const QModelIndex& index)
}
}
void GameListWidget::onTableViewContextMenuRequested(const QPoint& point)
void GameListWidget::onListViewContextMenuRequested(const QPoint& point)
{
emit entryContextMenuRequested(m_list_view->mapToGlobal(point));
}
void GameListWidget::onListViewItemActivated(const QModelIndex& index)
void GameListWidget::onGridViewItemActivated(const QModelIndex& index)
{
const QModelIndex source_index = m_sort_model->mapToSource(index);
if (!source_index.isValid() || source_index.row() >= static_cast<int>(GameList::GetEntryCount()))
@ -1434,80 +1382,11 @@ void GameListWidget::onListViewItemActivated(const QModelIndex& index)
emit entryActivated();
}
void GameListWidget::onListViewContextMenuRequested(const QPoint& point)
void GameListWidget::onGridViewContextMenuRequested(const QPoint& point)
{
emit entryContextMenuRequested(m_grid_view->mapToGlobal(point));
}
void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
{
QMenu menu;
for (int column = 0; column < GameListModel::Column_Count; column++)
{
if (column == GameListModel::Column_Cover)
continue;
QAction* action = menu.addAction(m_model->getColumnDisplayName(column));
action->setCheckable(true);
action->setChecked(!m_list_view->isColumnHidden(column));
connect(action, &QAction::toggled, [this, column](bool enabled) {
m_list_view->setColumnHidden(column, !enabled);
saveTableViewColumnVisibilitySettings(column);
resizeTableViewColumnsToFit();
});
}
menu.exec(m_list_view->mapToGlobal(point));
}
void GameListWidget::onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder)
{
saveTableViewColumnSortSettings();
}
void GameListWidget::onCoverScaleChanged()
{
QFont font;
font.setPointSizeF(20.0f * m_model->getCoverScale());
m_grid_view->setFont(font);
m_grid_view->updateLayout();
}
void GameListWidget::listZoom(float delta)
{
const float new_scale = std::clamp(m_model->getCoverScale() + delta, MIN_SCALE, MAX_SCALE);
Host::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
Host::CommitBaseSettingChanges();
m_model->setCoverScale(new_scale);
updateToolbar();
m_model->refresh();
}
void GameListWidget::gridZoomIn()
{
listZoom(0.05f);
}
void GameListWidget::gridZoomOut()
{
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);
Host::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
Host::CommitBaseSettingChanges();
m_model->setCoverScale(new_scale);
updateToolbar();
m_model->refresh();
}
void GameListWidget::refreshGridCovers()
{
m_model->refreshCovers();
@ -1545,7 +1424,7 @@ void GameListWidget::showGameList()
Host::CommitBaseSettingChanges();
m_ui.stack->setCurrentIndex(0);
setFocusProxy(m_list_view);
resizeTableViewColumnsToFit();
resizeListViewColumnsToFit();
updateToolbar();
emit layoutChanged();
}
@ -1637,126 +1516,22 @@ void GameListWidget::updateToolbar()
m_ui.gridScale->setEnabled(grid_view);
}
void GameListWidget::onCoverScaleChanged(float scale)
{
QSignalBlocker sb(m_ui.gridScale);
m_ui.gridScale->setValue(static_cast<int>(scale * 100.0f));
}
void GameListWidget::resizeEvent(QResizeEvent* event)
{
QWidget::resizeEvent(event);
resizeTableViewColumnsToFit();
resizeListViewColumnsToFit();
updateBackground(false);
}
void GameListWidget::resizeTableViewColumnsToFit()
void GameListWidget::resizeListViewColumnsToFit()
{
QtUtils::ResizeColumnsForTableView(m_list_view, {
45, // type
80, // code
-1, // title
-1, // file title
200, // developer
200, // publisher
200, // genre
50, // year
100, // players
85, // time played
85, // last played
80, // file size
80, // size
55, // region
100, // achievements
100 // compatibility
});
}
static TinyString getColumnVisibilitySettingsKeyName(int column)
{
return TinyString::from_format("Show{}", GameListModel::getColumnName(static_cast<GameListModel::Column>(column)));
}
void GameListWidget::loadTableViewColumnVisibilitySettings()
{
static constexpr std::array<bool, GameListModel::Column_Count> DEFAULT_VISIBILITY = {{
true, // type
true, // code
true, // title
false, // file title
false, // developer
false, // publisher
false, // genre
false, // year
false, // players
true, // time played
true, // last played
true, // file size
false, // size
true, // region
false, // achievements
false // compatibility
}};
for (int column = 0; column < GameListModel::Column_Count; column++)
{
const bool visible = Host::GetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column),
DEFAULT_VISIBILITY[column]);
m_list_view->setColumnHidden(column, !visible);
}
}
void GameListWidget::saveTableViewColumnVisibilitySettings()
{
for (int column = 0; column < GameListModel::Column_Count; column++)
{
const bool visible = !m_list_view->isColumnHidden(column);
Host::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column), visible);
Host::CommitBaseSettingChanges();
}
}
void GameListWidget::saveTableViewColumnVisibilitySettings(int column)
{
const bool visible = !m_list_view->isColumnHidden(column);
Host::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column), visible);
Host::CommitBaseSettingChanges();
}
void GameListWidget::loadTableViewColumnSortSettings()
{
const GameListModel::Column DEFAULT_SORT_COLUMN = GameListModel::Column_Icon;
const bool DEFAULT_SORT_DESCENDING = false;
const GameListModel::Column sort_column =
GameListModel::getColumnIdForName(Host::GetBaseStringSettingValue("GameListTableView", "SortColumn"))
.value_or(DEFAULT_SORT_COLUMN);
const bool sort_descending =
Host::GetBaseBoolSettingValue("GameListTableView", "SortDescending", DEFAULT_SORT_DESCENDING);
const Qt::SortOrder sort_order = sort_descending ? Qt::DescendingOrder : Qt::AscendingOrder;
m_sort_model->sort(sort_column, sort_order);
if (QHeaderView* hv = m_list_view->horizontalHeader())
hv->setSortIndicator(sort_column, sort_order);
}
void GameListWidget::saveTableViewColumnSortSettings()
{
const int sort_column = m_list_view->horizontalHeader()->sortIndicatorSection();
const bool sort_descending = (m_list_view->horizontalHeader()->sortIndicatorOrder() == Qt::DescendingOrder);
if (sort_column >= 0 && sort_column < GameListModel::Column_Count)
{
Host::SetBaseStringSettingValue("GameListTableView", "SortColumn",
GameListModel::getColumnName(static_cast<GameListModel::Column>(sort_column)));
}
Host::SetBaseBoolSettingValue("GameListTableView", "SortDescending", sort_descending);
Host::CommitBaseSettingChanges();
}
void GameListWidget::setTableViewColumnHidden(int column, bool hidden)
{
DebugAssert(column < GameListModel::Column_Count);
if (m_list_view->isColumnHidden(column) == hidden)
return;
m_list_view->setColumnHidden(column, hidden);
saveTableViewColumnVisibilitySettings(column);
resizeTableViewColumnsToFit();
m_list_view->resizeColumnsToFit();
}
const GameList::Entry* GameListWidget::getSelectedEntry() const
@ -1791,11 +1566,190 @@ const GameList::Entry* GameListWidget::getSelectedEntry() const
}
}
GameListGridListView::GameListGridListView(GameListModel* model, QWidget* parent) : QListView(parent), m_model(model)
GameListListView::GameListListView(GameListModel* model, GameListSortModel* sort_model, QWidget* parent)
: QTableView(parent), m_model(model), m_sort_model(sort_model)
{
setModel(sort_model);
setSortingEnabled(true);
setSelectionMode(QAbstractItemView::SingleSelection);
setSelectionBehavior(QAbstractItemView::SelectRows);
setContextMenuPolicy(Qt::CustomContextMenu);
setAlternatingRowColors(true);
setShowGrid(false);
setCurrentIndex({});
QHeaderView* const horizontal_header = horizontalHeader();
horizontal_header->setHighlightSections(false);
horizontal_header->setContextMenuPolicy(Qt::CustomContextMenu);
verticalHeader()->hide();
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
GameListCenterIconStyleDelegate* center_icon_delegate = new GameListCenterIconStyleDelegate(this);
setItemDelegateForColumn(GameListModel::Column_Icon, center_icon_delegate);
setItemDelegateForColumn(GameListModel::Column_Region, center_icon_delegate);
setItemDelegateForColumn(GameListModel::Column_Achievements,
new GameListAchievementsStyleDelegate(this, model, sort_model));
loadColumnVisibilitySettings();
loadColumnSortSettings();
connect(horizontal_header, &QHeaderView::sortIndicatorChanged, this, &GameListListView::onHeaderSortIndicatorChanged);
connect(horizontal_header, &QHeaderView::customContextMenuRequested, this,
&GameListListView::onHeaderContextMenuRequested);
}
void GameListGridListView::wheelEvent(QWheelEvent* e)
GameListListView::~GameListListView() = default;
void GameListListView::resizeColumnsToFit()
{
QtUtils::ResizeColumnsForTableView(this, {
45, // type
80, // code
-1, // title
-1, // file title
200, // developer
200, // publisher
200, // genre
50, // year
100, // players
85, // time played
85, // last played
80, // file size
80, // size
55, // region
100, // achievements
100 // compatibility
});
}
static TinyString getColumnVisibilitySettingsKeyName(int column)
{
return TinyString::from_format("Show{}", GameListModel::getColumnName(static_cast<GameListModel::Column>(column)));
}
void GameListListView::loadColumnVisibilitySettings()
{
static constexpr std::array<bool, GameListModel::Column_Count> DEFAULT_VISIBILITY = {{
true, // type
true, // code
true, // title
false, // file title
false, // developer
false, // publisher
false, // genre
false, // year
false, // players
true, // time played
true, // last played
true, // file size
false, // size
true, // region
false, // achievements
false // compatibility
}};
for (int column = 0; column < GameListModel::Column_Count; column++)
{
const bool visible = Host::GetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column),
DEFAULT_VISIBILITY[column]);
setColumnHidden(column, !visible);
}
}
void GameListListView::loadColumnSortSettings()
{
const GameListModel::Column DEFAULT_SORT_COLUMN = GameListModel::Column_Icon;
const bool DEFAULT_SORT_DESCENDING = false;
const GameListModel::Column sort_column =
GameListModel::getColumnIdForName(Host::GetBaseStringSettingValue("GameListTableView", "SortColumn"))
.value_or(DEFAULT_SORT_COLUMN);
const bool sort_descending =
Host::GetBaseBoolSettingValue("GameListTableView", "SortDescending", DEFAULT_SORT_DESCENDING);
const Qt::SortOrder sort_order = sort_descending ? Qt::DescendingOrder : Qt::AscendingOrder;
m_sort_model->sort(sort_column, sort_order);
if (QHeaderView* hv = horizontalHeader())
hv->setSortIndicator(sort_column, sort_order);
}
void GameListListView::saveColumnSortSettings()
{
const int sort_column = horizontalHeader()->sortIndicatorSection();
const bool sort_descending = (horizontalHeader()->sortIndicatorOrder() == Qt::DescendingOrder);
if (sort_column >= 0 && sort_column < GameListModel::Column_Count)
{
Host::SetBaseStringSettingValue("GameListTableView", "SortColumn",
GameListModel::getColumnName(static_cast<GameListModel::Column>(sort_column)));
}
Host::SetBaseBoolSettingValue("GameListTableView", "SortDescending", sort_descending);
Host::CommitBaseSettingChanges();
}
void GameListListView::setAndSaveColumnHidden(int column, bool hidden)
{
DebugAssert(column < GameListModel::Column_Count);
if (isColumnHidden(column) == hidden)
return;
setColumnHidden(column, hidden);
Host::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column), !hidden);
Host::CommitBaseSettingChanges();
resizeColumnsToFit();
}
void GameListListView::onHeaderSortIndicatorChanged(int, Qt::SortOrder)
{
saveColumnSortSettings();
}
void GameListListView::onHeaderContextMenuRequested(const QPoint& point)
{
QMenu menu;
for (int column = 0; column < GameListModel::Column_Count; column++)
{
if (column == GameListModel::Column_Cover)
continue;
QAction* action = menu.addAction(m_model->getColumnDisplayName(column));
action->setCheckable(true);
action->setChecked(!isColumnHidden(column));
connect(action, &QAction::toggled, [this, column](bool enabled) {
setAndSaveColumnHidden(column, !enabled);
resizeColumnsToFit();
});
}
menu.exec(mapToGlobal(point));
}
GameListGridView::GameListGridView(GameListModel* model, GameListSortModel* sort_model, QWidget* parent)
: QListView(parent), m_model(model)
{
setModel(sort_model);
setModelColumn(GameListModel::Column_Cover);
setSelectionMode(QAbstractItemView::SingleSelection);
setViewMode(QListView::IconMode);
setResizeMode(QListView::Adjust);
setUniformItemSizes(true);
setItemAlignment(Qt::AlignHCenter);
setContextMenuPolicy(Qt::CustomContextMenu);
setFrameStyle(QFrame::NoFrame);
setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
verticalScrollBar()->setSingleStep(15);
connect(m_model, &GameListModel::coverScaleChanged, this, &GameListGridView::onCoverScaleChanged);
}
GameListGridView::~GameListGridView() = default;
void GameListGridView::wheelEvent(QWheelEvent* e)
{
if (e->modifiers() & Qt::ControlModifier)
{
@ -1814,13 +1768,44 @@ void GameListGridListView::wheelEvent(QWheelEvent* e)
QListView::wheelEvent(e);
}
void GameListGridListView::resizeEvent(QResizeEvent* e)
void GameListGridView::resizeEvent(QResizeEvent* e)
{
QListView::resizeEvent(e);
updateLayout();
}
void GameListGridListView::updateLayout()
void GameListGridView::onCoverScaleChanged(float scale)
{
QFont font;
font.setPointSizeF(20.0f * scale);
setFont(font);
updateLayout();
}
void GameListGridView::adjustZoom(float delta)
{
const float new_scale = std::clamp(m_model->getCoverScale() + delta, MIN_SCALE, MAX_SCALE);
m_model->setCoverScale(new_scale);
}
void GameListGridView::zoomIn()
{
adjustZoom(0.05f);
}
void GameListGridView::zoomOut()
{
adjustZoom(-0.05f);
}
void GameListGridView::setZoomPct(int int_scale)
{
const float new_scale = std::clamp(static_cast<float>(int_scale) / 100.0f, MIN_SCALE, MAX_SCALE);
m_model->setCoverScale(new_scale);
}
void GameListGridView::updateLayout()
{
const QScrollBar* const vertical_scrollbar = verticalScrollBar();
const int scrollbar_width = vertical_scrollbar->isVisible() ? vertical_scrollbar->width() : 0;
@ -1848,12 +1833,12 @@ void GameListGridListView::updateLayout()
m_vertical_offset = item_spacing;
}
int GameListGridListView::horizontalOffset() const
int GameListGridView::horizontalOffset() const
{
return QListView::horizontalOffset() - m_horizontal_offset;
}
int GameListGridListView::verticalOffset() const
int GameListGridView::verticalOffset() const
{
return QListView::verticalOffset() - m_vertical_offset;
}

View File

@ -25,7 +25,6 @@
Q_DECLARE_METATYPE(const GameList::Entry*);
class GameListModel;
class GameListSortModel;
class GameListRefreshThread;
@ -60,7 +59,7 @@ public:
static std::optional<Column> getColumnIdForName(std::string_view name);
static const char* getColumnName(Column col);
GameListModel(float cover_scale, bool show_cover_titles, bool show_game_icons, QObject* parent = nullptr);
explicit GameListModel(QObject* parent);
~GameListModel();
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
@ -100,7 +99,7 @@ public:
void updateCacheSize(int num_rows, int num_columns);
Q_SIGNALS:
void coverScaleChanged();
void coverScaleChanged(float scale);
private Q_SLOTS:
void rowsChanged(const QList<int>& rows);
@ -111,6 +110,7 @@ private:
void loadCommonImages();
void loadThemeSpecificImages();
void setColumnDisplayNames();
void updateCoverScale();
void loadOrGenerateCover(const GameList::Entry* ge);
void invalidateCoverForPath(const std::string& path);
void coverLoaded(const std::string& path, const QImage& image, float scale);
@ -151,26 +151,58 @@ private:
mutable LRUCache<std::string, QPixmap> m_memcard_pixmap_cache;
};
class GameListGridListView final : public QListView
class GameListListView final : public QTableView
{
Q_OBJECT
public:
GameListGridListView(GameListModel* model, QWidget* parent);
GameListListView(GameListModel* model, GameListSortModel* sort_model, QWidget* parent);
~GameListListView() override;
void setAndSaveColumnHidden(int column, bool hidden);
void resizeColumnsToFit();
private Q_SLOTS:
void onHeaderSortIndicatorChanged(int, Qt::SortOrder);
void onHeaderContextMenuRequested(const QPoint& point);
private:
void loadColumnVisibilitySettings();
void loadColumnSortSettings();
void saveColumnSortSettings();
GameListModel* m_model = nullptr;
GameListSortModel* m_sort_model = nullptr;
};
class GameListGridView final : public QListView
{
Q_OBJECT
public:
GameListGridView(GameListModel* model, GameListSortModel* sort_model, QWidget* parent);
~GameListGridView() override;
void updateLayout();
int horizontalOffset() const override;
int verticalOffset() const override;
Q_SIGNALS:
public Q_SLOTS:
void zoomOut();
void zoomIn();
void setZoomPct(int int_scale);
protected:
void wheelEvent(QWheelEvent* e) override;
void resizeEvent(QResizeEvent* e) override;
private Q_SLOTS:
void onCoverScaleChanged(float scale);
private:
void adjustZoom(float delta);
GameListModel* m_model = nullptr;
int m_horizontal_offset = 0;
int m_vertical_offset = 0;
@ -185,10 +217,11 @@ public:
~GameListWidget();
ALWAYS_INLINE GameListModel* getModel() const { return m_model; }
ALWAYS_INLINE GameListListView* getListView() const { return m_list_view; }
ALWAYS_INLINE GameListGridView* getGridView() const { return m_grid_view; }
void initialize();
void resizeTableViewColumnsToFit();
void setTableViewColumnHidden(int column, bool hidden);
void resizeListViewColumnsToFit();
void refresh(bool invalidate_cache);
void refreshModel();
@ -219,14 +252,13 @@ private Q_SLOTS:
void onRefreshProgress(const QString& status, int current, int total, float time);
void onRefreshComplete();
void onCoverScaleChanged(float scale);
void onSelectionModelCurrentChanged(const QModelIndex& current, const QModelIndex& previous);
void onTableViewItemActivated(const QModelIndex& index);
void onTableViewContextMenuRequested(const QPoint& point);
void onTableViewHeaderContextMenuRequested(const QPoint& point);
void onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder);
void onListViewItemActivated(const QModelIndex& index);
void onListViewContextMenuRequested(const QPoint& point);
void onCoverScaleChanged();
void onGridViewItemActivated(const QModelIndex& index);
void onGridViewContextMenuRequested(const QPoint& point);
void onSearchReturnPressed();
public Q_SLOTS:
@ -235,9 +267,6 @@ public Q_SLOTS:
void setShowCoverTitles(bool enabled);
void setMergeDiscSets(bool enabled);
void setShowGameIcons(bool enabled);
void gridZoomIn();
void gridZoomOut();
void gridIntScale(int int_scale);
void refreshGridCovers();
void focusSearchWidget();
@ -245,20 +274,14 @@ protected:
void resizeEvent(QResizeEvent* event);
private:
void loadTableViewColumnVisibilitySettings();
void saveTableViewColumnVisibilitySettings();
void saveTableViewColumnVisibilitySettings(int column);
void loadTableViewColumnSortSettings();
void saveTableViewColumnSortSettings();
void listZoom(float delta);
void updateToolbar();
Ui::GameListWidget m_ui;
GameListModel* m_model = nullptr;
GameListSortModel* m_sort_model = nullptr;
QTableView* m_list_view = nullptr;
GameListGridListView* m_grid_view = nullptr;
GameListListView* m_list_view = nullptr;
GameListGridView* m_grid_view = nullptr;
QWidget* m_empty_widget = nullptr;
Ui::EmptyGameListWidget m_empty_ui;

View File

@ -449,7 +449,7 @@ void MainWindow::destroyDisplayWidget(bool show_game_list)
if (show_game_list)
{
m_ui.mainContainer->setCurrentIndex(0);
m_game_list_widget->resizeTableViewColumnsToFit();
m_game_list_widget->resizeListViewColumnsToFit();
}
}
@ -1323,13 +1323,13 @@ void MainWindow::onViewSystemDisplayTriggered()
void MainWindow::onViewGameGridZoomInActionTriggered()
{
if (isShowingGameList())
m_game_list_widget->gridZoomIn();
m_game_list_widget->getGridView()->zoomIn();
}
void MainWindow::onViewGameGridZoomOutActionTriggered()
{
if (isShowingGameList())
m_game_list_widget->gridZoomOut();
m_game_list_widget->getGridView()->zoomOut();
}
void MainWindow::onGitHubRepositoryActionTriggered()
@ -2441,7 +2441,7 @@ void MainWindow::showEvent(QShowEvent* event)
// gives the incorrect sizes for columns, if you set the style before setting up
// the rest of the window... so, instead, let's just force it to be resized on show.
if (isShowingGameList())
m_game_list_widget->resizeTableViewColumnsToFit();
m_game_list_widget->resizeListViewColumnsToFit();
}
void MainWindow::closeEvent(QCloseEvent* event)
@ -2754,7 +2754,7 @@ void MainWindow::onAchievementsLoginSuccess(const QString& username, quint32 poi
if (!Host::GetBaseBoolSettingValue("GameListTableView", "TriedShowingAchievementsColumn", false))
{
Host::SetBaseBoolSettingValue("GameListTableView", "TriedShowingAchievementsColumn", true);
m_game_list_widget->setTableViewColumnHidden(GameListModel::Column_Achievements, false);
m_game_list_widget->getListView()->setAndSaveColumnHidden(GameListModel::Column_Achievements, false);
}
}