mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
GameListWidget: Overhaul serialization of table header state
Some checks are pending
🐧 Linux Builds / AppImage (push) Waiting to run
🐧 Linux Builds / Flatpak (push) Waiting to run
🍎 MacOS Builds / Defaults (push) Waiting to run
🖥️ Windows Builds / Lint VS Project Files (push) Waiting to run
🖥️ Windows Builds / SSE4 (push) Blocked by required conditions
🖥️ Windows Builds / AVX2 (push) Blocked by required conditions
🖥️ Windows Builds / CMake (push) Waiting to run
Some checks are pending
🐧 Linux Builds / AppImage (push) Waiting to run
🐧 Linux Builds / Flatpak (push) Waiting to run
🍎 MacOS Builds / Defaults (push) Waiting to run
🖥️ Windows Builds / Lint VS Project Files (push) Waiting to run
🖥️ Windows Builds / SSE4 (push) Blocked by required conditions
🖥️ Windows Builds / AVX2 (push) Blocked by required conditions
🖥️ Windows Builds / CMake (push) Waiting to run
This commit is contained in:
parent
c8dffccaa7
commit
5a60259ef5
@ -45,6 +45,25 @@ static const char* SUPPORTED_FORMATS_STRING = QT_TRANSLATE_NOOP(GameListWidget,
|
|||||||
static constexpr float MIN_SCALE = 0.1f;
|
static constexpr float MIN_SCALE = 0.1f;
|
||||||
static constexpr float MAX_SCALE = 2.0f;
|
static constexpr float MAX_SCALE = 2.0f;
|
||||||
|
|
||||||
|
static constexpr GameListModel::Column DEFAULT_SORT_COLUMN = GameListModel::Column_Title;
|
||||||
|
static constexpr int DEFAULT_SORT_INDEX = static_cast<int>(DEFAULT_SORT_COLUMN);
|
||||||
|
static constexpr Qt::SortOrder DEFAULT_SORT_ORDER = Qt::AscendingOrder;
|
||||||
|
|
||||||
|
static constexpr std::array<int, GameListModel::Column_Count> DEFAULT_COLUMN_WIDTHS = {{
|
||||||
|
55, // type
|
||||||
|
85, // code
|
||||||
|
-1, // title
|
||||||
|
-1, // file title
|
||||||
|
75, // crc
|
||||||
|
95, // time played
|
||||||
|
90, // last played
|
||||||
|
80, // size
|
||||||
|
60, // region
|
||||||
|
120 // compatibility
|
||||||
|
}};
|
||||||
|
static_assert(static_cast<int>(DEFAULT_COLUMN_WIDTHS.size()) <= GameListModel::Column_Count,
|
||||||
|
"Game List: More default column widths than column types.");
|
||||||
|
|
||||||
class GameListSortModel final : public QSortFilterProxyModel
|
class GameListSortModel final : public QSortFilterProxyModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -235,6 +254,7 @@ void GameListWidget::initialize()
|
|||||||
m_table_view = new QTableView(m_ui.stack);
|
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->horizontalHeader()->setSectionsMovable(true);
|
||||||
m_table_view->setSelectionMode(QAbstractItemView::SingleSelection);
|
m_table_view->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
m_table_view->setSelectionBehavior(QAbstractItemView::SelectRows);
|
m_table_view->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
m_table_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
m_table_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
@ -252,18 +272,28 @@ void GameListWidget::initialize()
|
|||||||
m_table_view->setItemDelegateForColumn(8, new GameListIconStyleDelegate(this));
|
m_table_view->setItemDelegateForColumn(8, new GameListIconStyleDelegate(this));
|
||||||
m_table_view->setItemDelegateForColumn(9, new GameListIconStyleDelegate(this));
|
m_table_view->setItemDelegateForColumn(9, new GameListIconStyleDelegate(this));
|
||||||
|
|
||||||
loadTableViewColumnVisibilitySettings();
|
|
||||||
loadTableViewColumnSortSettings();
|
|
||||||
|
|
||||||
connect(m_table_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
connect(m_table_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||||
&GameListWidget::onSelectionModelCurrentChanged);
|
&GameListWidget::onSelectionModelCurrentChanged);
|
||||||
connect(m_table_view, &QTableView::activated, this, &GameListWidget::onTableViewItemActivated);
|
connect(m_table_view, &QTableView::activated, this, &GameListWidget::onTableViewItemActivated);
|
||||||
connect(m_table_view, &QTableView::customContextMenuRequested, this,
|
connect(m_table_view, &QTableView::customContextMenuRequested, this,
|
||||||
&GameListWidget::onTableViewContextMenuRequested);
|
&GameListWidget::onTableViewContextMenuRequested);
|
||||||
connect(m_table_view->horizontalHeader(), &QHeaderView::customContextMenuRequested, this,
|
connect(m_table_view->horizontalHeader(), &QHeaderView::customContextMenuRequested, this,
|
||||||
&GameListWidget::onTableViewHeaderContextMenuRequested);
|
&GameListWidget::onTableViewHeaderContextMenuRequested);
|
||||||
|
|
||||||
|
// Save state when header state changes (hiding and showing handled within onTableViewHeaderContextMenuRequested).
|
||||||
|
connect(m_table_view->horizontalHeader(), &QHeaderView::sectionMoved, this, &GameListWidget::onTableHeaderStateChanged);
|
||||||
|
connect(m_table_view->horizontalHeader(), &QHeaderView::sectionResized, this, &GameListWidget::onTableHeaderStateChanged);
|
||||||
connect(m_table_view->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this,
|
connect(m_table_view->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this,
|
||||||
&GameListWidget::saveTableViewColumnSortSettings);
|
[this](const int column, const Qt::SortOrder sort_order) { GameListWidget::saveSortSettings(column, sort_order); GameListWidget::onTableHeaderStateChanged(); });
|
||||||
|
|
||||||
|
// Load the last session's header state or create a new one.
|
||||||
|
if (Host::ContainsBaseSettingValue("GameListTableView", "HeaderState"))
|
||||||
|
loadTableHeaderState();
|
||||||
|
else
|
||||||
|
applyTableHeaderDefaults();
|
||||||
|
|
||||||
|
// After header state load to account for user-specified sort.
|
||||||
|
m_table_view->setSortingEnabled(true);
|
||||||
|
|
||||||
m_ui.stack->insertWidget(0, m_table_view);
|
m_ui.stack->insertWidget(0, m_table_view);
|
||||||
|
|
||||||
@ -525,18 +555,24 @@ void GameListWidget::onListViewContextMenuRequested(const QPoint& point)
|
|||||||
void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
|
void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
|
||||||
{
|
{
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
|
QHeaderView* header = m_table_view->horizontalHeader();
|
||||||
|
if (!header)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int column_visual = 0;
|
||||||
for (int column = 0; column < GameListModel::Column_Count; column++)
|
for (int column = 0; column < GameListModel::Column_Count; column++)
|
||||||
{
|
{
|
||||||
|
// The "cover" column is the game grid and cannot be hidden.
|
||||||
if (column == GameListModel::Column_Cover)
|
if (column == GameListModel::Column_Cover)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
QAction* action = menu.addAction(m_model->getColumnDisplayName(column));
|
column_visual = header->visualIndex(column);
|
||||||
|
QAction* action = menu.addAction(m_model->getColumnDisplayName(column_visual));
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
action->setChecked(!m_table_view->isColumnHidden(column));
|
action->setChecked(!m_table_view->isColumnHidden(column_visual));
|
||||||
connect(action, &QAction::toggled, [this, column](bool enabled) {
|
connect(action, &QAction::toggled, [this, column_visual](bool enabled) {
|
||||||
m_table_view->setColumnHidden(column, !enabled);
|
m_table_view->setColumnHidden(column_visual, !enabled);
|
||||||
saveTableViewColumnVisibilitySettings(column);
|
onTableHeaderStateChanged();
|
||||||
resizeTableViewColumnsToFit();
|
resizeTableViewColumnsToFit();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -697,91 +733,100 @@ bool GameListWidget::event(QEvent* event)
|
|||||||
void GameListWidget::resizeTableViewColumnsToFit()
|
void GameListWidget::resizeTableViewColumnsToFit()
|
||||||
{
|
{
|
||||||
QtUtils::ResizeColumnsForTableView(m_table_view, {
|
QtUtils::ResizeColumnsForTableView(m_table_view, {
|
||||||
55, // type
|
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Type],
|
||||||
85, // code
|
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Serial],
|
||||||
-1, // title
|
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_FileTitle],
|
||||||
-1, // file title
|
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Type],
|
||||||
75, // crc
|
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_CRC],
|
||||||
95, // time played
|
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_TimePlayed],
|
||||||
90, // last played
|
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_LastPlayed],
|
||||||
80, // size
|
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Size],
|
||||||
60, // region
|
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Region],
|
||||||
120, // compatibility
|
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Compatibility],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string getColumnVisibilitySettingsKeyName(int column)
|
void GameListWidget::loadTableHeaderState()
|
||||||
{
|
{
|
||||||
return StringUtil::StdStringFromFormat("Show%s",
|
QHeaderView* header = m_table_view->horizontalHeader();
|
||||||
|
if (!header)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Decode Base64 string from settings to QByteArray state.
|
||||||
|
const std::string state_setting = Host::GetBaseStringSettingValue("GameListTableView", "HeaderState");
|
||||||
|
if (state_setting.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QSignalBlocker blocker(header);
|
||||||
|
header->restoreState(QByteArray::fromBase64(QByteArray::fromStdString(state_setting)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameListWidget::onTableHeaderStateChanged()
|
||||||
|
{
|
||||||
|
QHeaderView* header = m_table_view->horizontalHeader();
|
||||||
|
if (!header)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Encode QByteArray state as Base64 string for storage.
|
||||||
|
Host::SetBaseStringSettingValue("GameListTableView", "HeaderState", header->saveState().toBase64());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameListWidget::applyTableHeaderDefaults()
|
||||||
|
{
|
||||||
|
QHeaderView* header = m_table_view->horizontalHeader();
|
||||||
|
if (!header)
|
||||||
|
return;
|
||||||
|
|
||||||
|
{
|
||||||
|
QSignalBlocker blocker(header);
|
||||||
|
header->hideSection(GameListModel::Column_FileTitle);
|
||||||
|
header->hideSection(GameListModel::Column_CRC);
|
||||||
|
header->hideSection(GameListModel::Column_Cover);
|
||||||
|
for (int column = 0; column < GameListModel::Column_Count; column++)
|
||||||
|
{
|
||||||
|
if (column == GameListModel::Column_Cover)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
header->resizeSection(column, DEFAULT_COLUMN_WIDTHS[column]);
|
||||||
|
}
|
||||||
|
header->setSortIndicator(DEFAULT_SORT_INDEX, DEFAULT_SORT_ORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
Host::SetBaseStringSettingValue("GameListTableView", "HeaderState", header->saveState().toBase64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (Tech): Create a button for this in the minibar. Currently unused.
|
||||||
|
void GameListWidget::resetTableHeaderToDefault()
|
||||||
|
{
|
||||||
|
QHeaderView* header = m_table_view->horizontalHeader();
|
||||||
|
if (!header)
|
||||||
|
return;
|
||||||
|
|
||||||
|
{
|
||||||
|
QSignalBlocker blocker(header);
|
||||||
|
for (int column = 0; column < GameListModel::Column_Count; column++)
|
||||||
|
{
|
||||||
|
if (column == GameListModel::Column_Cover)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Reset size, position, and visibility.
|
||||||
|
header->resizeSection(column, DEFAULT_COLUMN_WIDTHS[column]);
|
||||||
|
header->moveSection(header->visualIndex(column), column);
|
||||||
|
header->setSectionHidden(column,
|
||||||
|
column == GameListModel::Column_CRC || column == GameListModel::Column_FileTitle);
|
||||||
|
}
|
||||||
|
header->hideSection(GameListModel::Column_Cover);
|
||||||
|
header->setSortIndicator(DEFAULT_SORT_INDEX, DEFAULT_SORT_ORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
Host::SetBaseStringSettingValue("GameListTableView", "HeaderState", header->saveState().toBase64());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameListWidget::saveSortSettings(const int column, const Qt::SortOrder sort_order)
|
||||||
|
{
|
||||||
|
Host::SetBaseStringSettingValue("GameListTableView", "SortColumn",
|
||||||
GameListModel::getColumnName(static_cast<GameListModel::Column>(column)));
|
GameListModel::getColumnName(static_cast<GameListModel::Column>(column)));
|
||||||
}
|
Host::SetBaseBoolSettingValue("GameListTableView", "SortDescending", static_cast<bool>(sort_order));
|
||||||
|
|
||||||
void GameListWidget::loadTableViewColumnVisibilitySettings()
|
|
||||||
{
|
|
||||||
static constexpr std::array<bool, GameListModel::Column_Count> DEFAULT_VISIBILITY = {{
|
|
||||||
true, // type
|
|
||||||
true, // code
|
|
||||||
true, // title
|
|
||||||
false, // file title
|
|
||||||
false, // crc
|
|
||||||
true, // time played
|
|
||||||
true, // last played
|
|
||||||
true, // size
|
|
||||||
true, // region
|
|
||||||
true // compatibility
|
|
||||||
}};
|
|
||||||
|
|
||||||
for (int column = 0; column < GameListModel::Column_Count; column++)
|
|
||||||
{
|
|
||||||
const bool visible = Host::GetBaseBoolSettingValue(
|
|
||||||
"GameListTableView", getColumnVisibilitySettingsKeyName(column).c_str(), DEFAULT_VISIBILITY[column]);
|
|
||||||
m_table_view->setColumnHidden(column, !visible);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameListWidget::saveTableViewColumnVisibilitySettings()
|
|
||||||
{
|
|
||||||
for (int column = 0; column < GameListModel::Column_Count; column++)
|
|
||||||
{
|
|
||||||
const bool visible = !m_table_view->isColumnHidden(column);
|
|
||||||
Host::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column).c_str(), visible);
|
|
||||||
Host::CommitBaseSettingChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameListWidget::saveTableViewColumnVisibilitySettings(int column)
|
|
||||||
{
|
|
||||||
const bool visible = !m_table_view->isColumnHidden(column);
|
|
||||||
Host::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column).c_str(), visible);
|
|
||||||
Host::CommitBaseSettingChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameListWidget::loadTableViewColumnSortSettings()
|
|
||||||
{
|
|
||||||
const GameListModel::Column DEFAULT_SORT_COLUMN = GameListModel::Column_Type;
|
|
||||||
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_table_view->horizontalHeader())
|
|
||||||
hv->setSortIndicator(sort_column, sort_order);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameListWidget::saveTableViewColumnSortSettings(const int sort_column, const Qt::SortOrder sort_order)
|
|
||||||
{
|
|
||||||
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_order == Qt::DescendingOrder);
|
|
||||||
Host::CommitBaseSettingChanges();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<GameList::Entry> GameListWidget::getSelectedEntry() const
|
std::optional<GameList::Entry> GameListWidget::getSelectedEntry() const
|
||||||
|
|||||||
@ -85,6 +85,7 @@ private Q_SLOTS:
|
|||||||
void onListViewItemActivated(const QModelIndex& index);
|
void onListViewItemActivated(const QModelIndex& index);
|
||||||
void onListViewContextMenuRequested(const QPoint& point);
|
void onListViewContextMenuRequested(const QPoint& point);
|
||||||
void onCoverScaleChanged();
|
void onCoverScaleChanged();
|
||||||
|
void onTableHeaderStateChanged();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void showGameList();
|
void showGameList();
|
||||||
@ -102,11 +103,10 @@ protected:
|
|||||||
bool event(QEvent* event) override;
|
bool event(QEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadTableViewColumnVisibilitySettings();
|
void loadTableHeaderState();
|
||||||
void saveTableViewColumnVisibilitySettings();
|
void applyTableHeaderDefaults();
|
||||||
void saveTableViewColumnVisibilitySettings(int column);
|
void resetTableHeaderToDefault();
|
||||||
void loadTableViewColumnSortSettings();
|
void saveSortSettings(int column, Qt::SortOrder sort_order);
|
||||||
void saveTableViewColumnSortSettings(const int sort_column, const Qt::SortOrder sort_order);
|
|
||||||
void listZoom(float delta);
|
void listZoom(float delta);
|
||||||
void updateToolbar();
|
void updateToolbar();
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user