mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-06 19:45:33 +00:00
Qt: Improve game grid layout calculations
Use grid size instead of icon size/spacing. Fixes the number of columns changing when different items are visible. Also restores the old behaviour of dynamic scroll bar visibility.
This commit is contained in:
parent
cb751b0990
commit
22089e9b75
@ -15,6 +15,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/file_system.h"
|
||||
#include "common/log.h"
|
||||
#include "common/path.h"
|
||||
#include "common/string_util.h"
|
||||
|
||||
@ -32,6 +33,8 @@
|
||||
#include <QtWidgets/QStyledItemDelegate>
|
||||
#include <algorithm>
|
||||
|
||||
LOG_CHANNEL(GameList);
|
||||
|
||||
static constexpr float MIN_SCALE = 0.1f;
|
||||
static constexpr float MAX_SCALE = 2.0f;
|
||||
|
||||
@ -47,10 +50,10 @@ static constexpr std::array<const char*, GameListModel::Column_Count> s_column_n
|
||||
{"Icon", "Serial", "Title", "File Title", "Developer", "Publisher", "Genre", "Year", "Players", "Time Played",
|
||||
"Last Played", "Size", "File Size", "Region", "Achievements", "Compatibility", "Cover"}};
|
||||
|
||||
static constexpr int COVER_ART_WIDTH = 512;
|
||||
static constexpr int COVER_ART_HEIGHT = 512;
|
||||
static constexpr int COVER_ART_SIZE = 512;
|
||||
static constexpr int COVER_ART_SPACING = 32;
|
||||
static constexpr int MIN_COVER_CACHE_SIZE = 256;
|
||||
static constexpr int MIN_COVER_CACHE_ROW_BUFFER = 4;
|
||||
|
||||
static void resizeAndPadImage(QImage* image, int expected_width, int expected_height, bool fill_with_top_left)
|
||||
{
|
||||
@ -159,11 +162,11 @@ void GameListModel::setCoverScale(float scale)
|
||||
if (loading_image.load(QStringLiteral("%1/images/placeholder.png").arg(QtHost::GetResourcesBasePath())))
|
||||
{
|
||||
loading_image.setDevicePixelRatio(dpr);
|
||||
resizeAndPadImage(&loading_image, getCoverArtWidth(), getCoverArtHeight(), false);
|
||||
resizeAndPadImage(&loading_image, getCoverArtSize(), getCoverArtSize(), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
loading_image = QImage(getCoverArtWidth(), getCoverArtHeight(), QImage::Format_RGB32);
|
||||
loading_image = QImage(getCoverArtSize(), getCoverArtSize(), QImage::Format_RGB32);
|
||||
loading_image.setDevicePixelRatio(dpr);
|
||||
loading_image.fill(QColor(0, 0, 0, 0));
|
||||
}
|
||||
@ -173,11 +176,11 @@ void GameListModel::setCoverScale(float scale)
|
||||
if (m_placeholder_image.load(QStringLiteral("%1/images/cover-placeholder.png").arg(QtHost::GetResourcesBasePath())))
|
||||
{
|
||||
m_placeholder_image.setDevicePixelRatio(dpr);
|
||||
resizeAndPadImage(&m_placeholder_image, getCoverArtWidth(), getCoverArtHeight(), false);
|
||||
resizeAndPadImage(&m_placeholder_image, getCoverArtSize(), getCoverArtSize(), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_placeholder_image = QImage(getCoverArtWidth(), getCoverArtHeight(), QImage::Format_RGB32);
|
||||
m_placeholder_image = QImage(getCoverArtSize(), getCoverArtSize(), QImage::Format_RGB32);
|
||||
m_placeholder_image.setDevicePixelRatio(dpr);
|
||||
m_placeholder_image.fill(QColor(0, 0, 0, 0));
|
||||
}
|
||||
@ -191,14 +194,13 @@ void GameListModel::refreshCovers()
|
||||
refresh();
|
||||
}
|
||||
|
||||
void GameListModel::updateCacheSize(int width, int height)
|
||||
void GameListModel::updateCacheSize(int num_rows, int num_columns)
|
||||
{
|
||||
// Add additional buffer zone to the rows, since Qt will grab them early when scrolling.
|
||||
const int num_items = (num_rows + MIN_COVER_CACHE_ROW_BUFFER) * num_columns;
|
||||
|
||||
// This is a bit conversative, since it doesn't consider padding, but better to be over than under.
|
||||
const int cover_width = getCoverArtWidth();
|
||||
const int cover_height = getCoverArtHeight();
|
||||
const int num_columns = ((width + (cover_width - 1)) / cover_width);
|
||||
const int num_rows = ((height + (cover_height - 1)) / cover_height);
|
||||
m_cover_pixmap_cache.SetMaxCapacity(static_cast<int>(std::max(num_columns * num_rows, MIN_COVER_CACHE_SIZE)));
|
||||
m_cover_pixmap_cache.SetMaxCapacity(static_cast<int>(std::max(num_items, MIN_COVER_CACHE_SIZE)));
|
||||
}
|
||||
|
||||
void GameListModel::reloadThemeSpecificImages()
|
||||
@ -210,8 +212,8 @@ void GameListModel::reloadThemeSpecificImages()
|
||||
void GameListModel::loadOrGenerateCover(const GameList::Entry* ge)
|
||||
{
|
||||
QtAsyncTask::create(this, [path = ge->path, serial = ge->serial, title = ge->title,
|
||||
placeholder_image = m_placeholder_image, list = this, width = getCoverArtWidth(),
|
||||
height = getCoverArtHeight(), scale = m_cover_scale,
|
||||
placeholder_image = m_placeholder_image, list = this, width = getCoverArtSize(),
|
||||
height = getCoverArtSize(), scale = m_cover_scale,
|
||||
dpr = qApp->devicePixelRatio()]() mutable {
|
||||
QImage image;
|
||||
loadOrGenerateCover(image, placeholder_image, width, height, scale, dpr, path, serial, title);
|
||||
@ -433,14 +435,9 @@ void GameListModel::fixIconPixmapSize(QPixmap& pm)
|
||||
pm = pm.scaled(new_width, new_height);
|
||||
}
|
||||
|
||||
int GameListModel::getCoverArtWidth() const
|
||||
int GameListModel::getCoverArtSize() const
|
||||
{
|
||||
return std::max(static_cast<int>(static_cast<float>(COVER_ART_WIDTH) * m_cover_scale), 1);
|
||||
}
|
||||
|
||||
int GameListModel::getCoverArtHeight() const
|
||||
{
|
||||
return std::max(static_cast<int>(static_cast<float>(COVER_ART_HEIGHT) * m_cover_scale), 1);
|
||||
return std::max(static_cast<int>(static_cast<float>(COVER_ART_SIZE) * m_cover_scale), 1);
|
||||
}
|
||||
|
||||
int GameListModel::getCoverArtSpacing() const
|
||||
@ -1114,6 +1111,25 @@ 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)
|
||||
@ -1129,7 +1145,6 @@ void GameListWidget::initialize()
|
||||
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->updateCacheSize(width(), height());
|
||||
|
||||
m_sort_model = new GameListSortModel(m_model);
|
||||
m_sort_model->setSourceModel(m_model);
|
||||
@ -1165,65 +1180,64 @@ void GameListWidget::initialize()
|
||||
connect(m_ui.searchText, &QLineEdit::returnPressed, this, &GameListWidget::onSearchReturnPressed);
|
||||
|
||||
GameListCenterIconStyleDelegate* center_icon_delegate = new GameListCenterIconStyleDelegate(this);
|
||||
m_table_view = new QTableView(m_ui.stack);
|
||||
m_table_view->setModel(m_sort_model);
|
||||
m_table_view->setSortingEnabled(true);
|
||||
m_table_view->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_table_view->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_table_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_table_view->setAlternatingRowColors(true);
|
||||
m_table_view->setShowGrid(false);
|
||||
m_table_view->setCurrentIndex({});
|
||||
m_table_view->horizontalHeader()->setHighlightSections(false);
|
||||
m_table_view->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_table_view->verticalHeader()->hide();
|
||||
m_table_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
m_table_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
|
||||
m_table_view->setItemDelegateForColumn(GameListModel::Column_Icon, center_icon_delegate);
|
||||
m_table_view->setItemDelegateForColumn(GameListModel::Column_Region, center_icon_delegate);
|
||||
m_table_view->setItemDelegateForColumn(GameListModel::Column_Achievements,
|
||||
new GameListAchievementsStyleDelegate(this, m_model, m_sort_model));
|
||||
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_table_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||
connect(m_list_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||
&GameListWidget::onSelectionModelCurrentChanged);
|
||||
connect(m_table_view, &QTableView::activated, this, &GameListWidget::onTableViewItemActivated);
|
||||
connect(m_table_view, &QTableView::customContextMenuRequested, this,
|
||||
&GameListWidget::onTableViewContextMenuRequested);
|
||||
connect(m_table_view->horizontalHeader(), &QHeaderView::customContextMenuRequested, this,
|
||||
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_table_view->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this,
|
||||
connect(m_list_view->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this,
|
||||
&GameListWidget::onTableViewHeaderSortIndicatorChanged);
|
||||
|
||||
m_ui.stack->insertWidget(0, m_table_view);
|
||||
m_ui.stack->insertWidget(0, m_list_view);
|
||||
|
||||
m_list_view = new GameListGridListView(m_ui.stack);
|
||||
m_list_view->setModel(m_sort_model);
|
||||
m_list_view->setModelColumn(GameListModel::Column_Cover);
|
||||
m_list_view->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_list_view->setViewMode(QListView::IconMode);
|
||||
m_list_view->setResizeMode(QListView::Adjust);
|
||||
m_list_view->setUniformItemSizes(true);
|
||||
m_list_view->setItemAlignment(Qt::AlignHCenter);
|
||||
m_list_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_list_view->setFrameStyle(QFrame::NoFrame);
|
||||
m_list_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
|
||||
m_list_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
m_list_view->verticalScrollBar()->setSingleStep(15);
|
||||
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->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||
connect(m_grid_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||
&GameListWidget::onSelectionModelCurrentChanged);
|
||||
connect(m_list_view, &GameListGridListView::zoomIn, this, &GameListWidget::gridZoomIn);
|
||||
connect(m_list_view, &GameListGridListView::zoomOut, this, &GameListWidget::gridZoomOut);
|
||||
connect(m_list_view, &QListView::activated, this, &GameListWidget::onListViewItemActivated);
|
||||
connect(m_list_view, &QListView::customContextMenuRequested, this, &GameListWidget::onListViewContextMenuRequested);
|
||||
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);
|
||||
|
||||
m_ui.stack->insertWidget(1, m_list_view);
|
||||
m_ui.stack->insertWidget(1, m_grid_view);
|
||||
|
||||
m_empty_widget = new QWidget(m_ui.stack);
|
||||
m_empty_ui.setupUi(m_empty_widget);
|
||||
@ -1237,7 +1251,7 @@ void GameListWidget::initialize()
|
||||
m_ui.stack->setCurrentIndex(1);
|
||||
else
|
||||
m_ui.stack->setCurrentIndex(0);
|
||||
setFocusProxy(grid_view ? static_cast<QWidget*>(m_list_view) : static_cast<QWidget*>(m_table_view));
|
||||
setFocusProxy(grid_view ? static_cast<QWidget*>(m_grid_view) : static_cast<QWidget*>(m_list_view));
|
||||
|
||||
updateToolbar();
|
||||
resizeTableViewColumnsToFit();
|
||||
@ -1321,7 +1335,7 @@ void GameListWidget::updateBackground(bool reload_image)
|
||||
if (m_background_image.isNull())
|
||||
{
|
||||
m_ui.stack->setPalette(palette());
|
||||
m_table_view->setAlternatingRowColors(true);
|
||||
m_list_view->setAlternatingRowColors(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1336,7 +1350,7 @@ void GameListWidget::updateBackground(bool reload_image)
|
||||
QPalette new_palette(m_ui.stack->palette());
|
||||
new_palette.setBrush(QPalette::Base, QPixmap::fromImage(image));
|
||||
m_ui.stack->setPalette(new_palette);
|
||||
m_table_view->setAlternatingRowColors(false);
|
||||
m_list_view->setAlternatingRowColors(false);
|
||||
};
|
||||
});
|
||||
}
|
||||
@ -1353,7 +1367,7 @@ void GameListWidget::onRefreshProgress(const QString& status, int current, int t
|
||||
{
|
||||
const bool grid_view = Host::GetBaseBoolSettingValue("UI", "GameListGridView", false);
|
||||
m_ui.stack->setCurrentIndex(grid_view ? 1 : 0);
|
||||
setFocusProxy(grid_view ? static_cast<QWidget*>(m_list_view) : static_cast<QWidget*>(m_table_view));
|
||||
setFocusProxy(grid_view ? static_cast<QWidget*>(m_grid_view) : static_cast<QWidget*>(m_list_view));
|
||||
}
|
||||
|
||||
if (!m_model->hasTakenGameList() || time >= SHORT_REFRESH_TIME)
|
||||
@ -1408,7 +1422,7 @@ void GameListWidget::onTableViewItemActivated(const QModelIndex& index)
|
||||
|
||||
void GameListWidget::onTableViewContextMenuRequested(const QPoint& point)
|
||||
{
|
||||
emit entryContextMenuRequested(m_table_view->mapToGlobal(point));
|
||||
emit entryContextMenuRequested(m_list_view->mapToGlobal(point));
|
||||
}
|
||||
|
||||
void GameListWidget::onListViewItemActivated(const QModelIndex& index)
|
||||
@ -1422,7 +1436,7 @@ void GameListWidget::onListViewItemActivated(const QModelIndex& index)
|
||||
|
||||
void GameListWidget::onListViewContextMenuRequested(const QPoint& point)
|
||||
{
|
||||
emit entryContextMenuRequested(m_list_view->mapToGlobal(point));
|
||||
emit entryContextMenuRequested(m_grid_view->mapToGlobal(point));
|
||||
}
|
||||
|
||||
void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
|
||||
@ -1436,15 +1450,15 @@ void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
|
||||
|
||||
QAction* action = menu.addAction(m_model->getColumnDisplayName(column));
|
||||
action->setCheckable(true);
|
||||
action->setChecked(!m_table_view->isColumnHidden(column));
|
||||
action->setChecked(!m_list_view->isColumnHidden(column));
|
||||
connect(action, &QAction::toggled, [this, column](bool enabled) {
|
||||
m_table_view->setColumnHidden(column, !enabled);
|
||||
m_list_view->setColumnHidden(column, !enabled);
|
||||
saveTableViewColumnVisibilitySettings(column);
|
||||
resizeTableViewColumnsToFit();
|
||||
});
|
||||
}
|
||||
|
||||
menu.exec(m_table_view->mapToGlobal(point));
|
||||
menu.exec(m_list_view->mapToGlobal(point));
|
||||
}
|
||||
|
||||
void GameListWidget::onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder)
|
||||
@ -1454,16 +1468,11 @@ void GameListWidget::onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder)
|
||||
|
||||
void GameListWidget::onCoverScaleChanged()
|
||||
{
|
||||
m_model->updateCacheSize(width(), height());
|
||||
|
||||
m_list_view->setSpacing(m_model->getCoverArtSpacing());
|
||||
m_list_view->setIconSize(QSize(m_model->getCoverArtWidth(), m_model->getCoverArtHeight()));
|
||||
|
||||
QFont font;
|
||||
font.setPointSizeF(20.0f * m_model->getCoverScale());
|
||||
m_list_view->setFont(font);
|
||||
m_grid_view->setFont(font);
|
||||
|
||||
m_list_view->updateLayout();
|
||||
m_grid_view->updateLayout();
|
||||
}
|
||||
|
||||
void GameListWidget::listZoom(float delta)
|
||||
@ -1518,7 +1527,7 @@ void GameListWidget::onSearchReturnPressed()
|
||||
return;
|
||||
|
||||
QAbstractItemView* const target =
|
||||
isShowingGameGrid() ? static_cast<QAbstractItemView*>(m_list_view) : static_cast<QAbstractItemView*>(m_table_view);
|
||||
isShowingGameGrid() ? static_cast<QAbstractItemView*>(m_grid_view) : static_cast<QAbstractItemView*>(m_list_view);
|
||||
target->selectionModel()->select(m_sort_model->index(0, 0),
|
||||
QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||
target->setFocus(Qt::ShortcutFocusReason);
|
||||
@ -1535,7 +1544,7 @@ void GameListWidget::showGameList()
|
||||
Host::SetBaseBoolSettingValue("UI", "GameListGridView", false);
|
||||
Host::CommitBaseSettingChanges();
|
||||
m_ui.stack->setCurrentIndex(0);
|
||||
setFocusProxy(m_table_view);
|
||||
setFocusProxy(m_list_view);
|
||||
resizeTableViewColumnsToFit();
|
||||
updateToolbar();
|
||||
emit layoutChanged();
|
||||
@ -1552,7 +1561,7 @@ void GameListWidget::showGameGrid()
|
||||
Host::SetBaseBoolSettingValue("UI", "GameListGridView", true);
|
||||
Host::CommitBaseSettingChanges();
|
||||
m_ui.stack->setCurrentIndex(1);
|
||||
setFocusProxy(m_list_view);
|
||||
setFocusProxy(m_grid_view);
|
||||
updateToolbar();
|
||||
emit layoutChanged();
|
||||
}
|
||||
@ -1568,6 +1577,7 @@ void GameListWidget::setShowCoverTitles(bool enabled)
|
||||
Host::SetBaseBoolSettingValue("UI", "GameListShowCoverTitles", enabled);
|
||||
Host::CommitBaseSettingChanges();
|
||||
m_model->setShowCoverTitles(enabled);
|
||||
m_grid_view->updateLayout();
|
||||
if (isShowingGameGrid())
|
||||
m_model->refresh();
|
||||
updateToolbar();
|
||||
@ -1636,24 +1646,24 @@ void GameListWidget::resizeEvent(QResizeEvent* event)
|
||||
|
||||
void GameListWidget::resizeTableViewColumnsToFit()
|
||||
{
|
||||
QtUtils::ResizeColumnsForTableView(m_table_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
|
||||
});
|
||||
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)
|
||||
@ -1686,7 +1696,7 @@ void GameListWidget::loadTableViewColumnVisibilitySettings()
|
||||
{
|
||||
const bool visible = Host::GetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column),
|
||||
DEFAULT_VISIBILITY[column]);
|
||||
m_table_view->setColumnHidden(column, !visible);
|
||||
m_list_view->setColumnHidden(column, !visible);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1694,7 +1704,7 @@ void GameListWidget::saveTableViewColumnVisibilitySettings()
|
||||
{
|
||||
for (int column = 0; column < GameListModel::Column_Count; column++)
|
||||
{
|
||||
const bool visible = !m_table_view->isColumnHidden(column);
|
||||
const bool visible = !m_list_view->isColumnHidden(column);
|
||||
Host::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column), visible);
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
@ -1702,7 +1712,7 @@ void GameListWidget::saveTableViewColumnVisibilitySettings()
|
||||
|
||||
void GameListWidget::saveTableViewColumnVisibilitySettings(int column)
|
||||
{
|
||||
const bool visible = !m_table_view->isColumnHidden(column);
|
||||
const bool visible = !m_list_view->isColumnHidden(column);
|
||||
Host::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column), visible);
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
@ -1719,14 +1729,14 @@ void GameListWidget::loadTableViewColumnSortSettings()
|
||||
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_table_view->horizontalHeader())
|
||||
if (QHeaderView* hv = m_list_view->horizontalHeader())
|
||||
hv->setSortIndicator(sort_column, sort_order);
|
||||
}
|
||||
|
||||
void GameListWidget::saveTableViewColumnSortSettings()
|
||||
{
|
||||
const int sort_column = m_table_view->horizontalHeader()->sortIndicatorSection();
|
||||
const bool sort_descending = (m_table_view->horizontalHeader()->sortIndicatorOrder() == Qt::DescendingOrder);
|
||||
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)
|
||||
{
|
||||
@ -1741,10 +1751,10 @@ void GameListWidget::saveTableViewColumnSortSettings()
|
||||
void GameListWidget::setTableViewColumnHidden(int column, bool hidden)
|
||||
{
|
||||
DebugAssert(column < GameListModel::Column_Count);
|
||||
if (m_table_view->isColumnHidden(column) == hidden)
|
||||
if (m_list_view->isColumnHidden(column) == hidden)
|
||||
return;
|
||||
|
||||
m_table_view->setColumnHidden(column, hidden);
|
||||
m_list_view->setColumnHidden(column, hidden);
|
||||
saveTableViewColumnVisibilitySettings(column);
|
||||
resizeTableViewColumnsToFit();
|
||||
}
|
||||
@ -1753,7 +1763,7 @@ const GameList::Entry* GameListWidget::getSelectedEntry() const
|
||||
{
|
||||
if (m_ui.stack->currentIndex() == 0)
|
||||
{
|
||||
const QItemSelectionModel* selection_model = m_table_view->selectionModel();
|
||||
const QItemSelectionModel* selection_model = m_list_view->selectionModel();
|
||||
if (!selection_model->hasSelection())
|
||||
return nullptr;
|
||||
|
||||
@ -1769,7 +1779,7 @@ const GameList::Entry* GameListWidget::getSelectedEntry() const
|
||||
}
|
||||
else
|
||||
{
|
||||
const QItemSelectionModel* selection_model = m_list_view->selectionModel();
|
||||
const QItemSelectionModel* selection_model = m_grid_view->selectionModel();
|
||||
if (!selection_model->hasSelection())
|
||||
return nullptr;
|
||||
|
||||
@ -1781,7 +1791,7 @@ const GameList::Entry* GameListWidget::getSelectedEntry() const
|
||||
}
|
||||
}
|
||||
|
||||
GameListGridListView::GameListGridListView(QWidget* parent /*= nullptr*/) : QListView(parent)
|
||||
GameListGridListView::GameListGridListView(GameListModel* model, QWidget* parent) : QListView(parent), m_model(model)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1806,26 +1816,44 @@ void GameListGridListView::wheelEvent(QWheelEvent* e)
|
||||
|
||||
void GameListGridListView::resizeEvent(QResizeEvent* e)
|
||||
{
|
||||
updateLayout();
|
||||
QListView::resizeEvent(e);
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
void GameListGridListView::updateLayout()
|
||||
{
|
||||
const int scrollbar_width = verticalScrollBar()->width();
|
||||
const int item_spacing = spacing();
|
||||
const int icon_margin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr, this) * 2;
|
||||
const QScrollBar* const vertical_scrollbar = verticalScrollBar();
|
||||
const int scrollbar_width = vertical_scrollbar->isVisible() ? vertical_scrollbar->width() : 0;
|
||||
const int icon_width = m_model->getCoverArtSize();
|
||||
const int item_spacing = m_model->getCoverArtSpacing();
|
||||
const int item_margin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr, this);
|
||||
|
||||
// Split margin+spacing evenly across both sides of each item.
|
||||
// I hate this +2. Not sure what's not being accounted for, but without it the calculation is off by 2 pixels...
|
||||
const int icon_width = iconSize().width() + icon_margin + item_spacing + 2;
|
||||
const int available_width = width() - scrollbar_width - item_spacing - icon_margin;
|
||||
const int items_per_row = available_width / icon_width;
|
||||
const int margin = (available_width - (items_per_row * icon_width)) / 2;
|
||||
const int item_width = icon_width + item_margin + item_spacing + 2;
|
||||
|
||||
// one line of text
|
||||
const int item_height = item_width + (m_model->getShowCoverTitles() ? QFontMetrics(font()).height() : 0);
|
||||
|
||||
const int available_width = width() - scrollbar_width;
|
||||
const int num_columns = available_width / item_width;
|
||||
const int num_rows = (height() + (item_height - 1)) / item_height;
|
||||
const int margin = (available_width - (num_columns * item_width)) / 2;
|
||||
|
||||
setGridSize(QSize(item_width, item_height));
|
||||
|
||||
m_model->updateCacheSize(num_rows, num_columns);
|
||||
|
||||
m_horizontal_offset = margin;
|
||||
m_vertical_offset = item_spacing;
|
||||
}
|
||||
|
||||
int GameListGridListView::horizontalOffset() const
|
||||
{
|
||||
return QListView::horizontalOffset() - m_horizontal_offset;
|
||||
}
|
||||
|
||||
int GameListGridListView::verticalOffset() const
|
||||
{
|
||||
return QListView::verticalOffset() - m_vertical_offset;
|
||||
}
|
||||
|
@ -94,11 +94,10 @@ public:
|
||||
|
||||
float getCoverScale() const { return m_cover_scale; }
|
||||
void setCoverScale(float scale);
|
||||
int getCoverArtWidth() const;
|
||||
int getCoverArtHeight() const;
|
||||
int getCoverArtSize() const;
|
||||
int getCoverArtSpacing() const;
|
||||
void refreshCovers();
|
||||
void updateCacheSize(int width, int height);
|
||||
void updateCacheSize(int num_rows, int num_columns);
|
||||
|
||||
Q_SIGNALS:
|
||||
void coverScaleChanged();
|
||||
@ -157,10 +156,11 @@ class GameListGridListView final : public QListView
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GameListGridListView(QWidget* parent = nullptr);
|
||||
GameListGridListView(GameListModel* model, QWidget* parent);
|
||||
|
||||
void updateLayout();
|
||||
int horizontalOffset() const override;
|
||||
int verticalOffset() const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void zoomOut();
|
||||
@ -171,7 +171,9 @@ protected:
|
||||
void resizeEvent(QResizeEvent* e) override;
|
||||
|
||||
private:
|
||||
GameListModel* m_model = nullptr;
|
||||
int m_horizontal_offset = 0;
|
||||
int m_vertical_offset = 0;
|
||||
};
|
||||
|
||||
class GameListWidget final : public QWidget
|
||||
@ -255,8 +257,8 @@ private:
|
||||
|
||||
GameListModel* m_model = nullptr;
|
||||
GameListSortModel* m_sort_model = nullptr;
|
||||
QTableView* m_table_view = nullptr;
|
||||
GameListGridListView* m_list_view = nullptr;
|
||||
QTableView* m_list_view = nullptr;
|
||||
GameListGridListView* m_grid_view = nullptr;
|
||||
|
||||
QWidget* m_empty_widget = nullptr;
|
||||
Ui::EmptyGameListWidget m_empty_ui;
|
||||
|
Loading…
x
Reference in New Issue
Block a user