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 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
|
||||
{
|
||||
public:
|
||||
@ -235,6 +254,7 @@ void GameListWidget::initialize()
|
||||
m_table_view = new QTableView(m_ui.stack);
|
||||
m_table_view->setModel(m_sort_model);
|
||||
m_table_view->setSortingEnabled(true);
|
||||
m_table_view->horizontalHeader()->setSectionsMovable(true);
|
||||
m_table_view->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_table_view->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_table_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
@ -252,9 +272,6 @@ void GameListWidget::initialize()
|
||||
m_table_view->setItemDelegateForColumn(8, new GameListIconStyleDelegate(this));
|
||||
m_table_view->setItemDelegateForColumn(9, new GameListIconStyleDelegate(this));
|
||||
|
||||
loadTableViewColumnVisibilitySettings();
|
||||
loadTableViewColumnSortSettings();
|
||||
|
||||
connect(m_table_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||
&GameListWidget::onSelectionModelCurrentChanged);
|
||||
connect(m_table_view, &QTableView::activated, this, &GameListWidget::onTableViewItemActivated);
|
||||
@ -262,8 +279,21 @@ void GameListWidget::initialize()
|
||||
&GameListWidget::onTableViewContextMenuRequested);
|
||||
connect(m_table_view->horizontalHeader(), &QHeaderView::customContextMenuRequested, this,
|
||||
&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,
|
||||
&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);
|
||||
|
||||
@ -525,18 +555,24 @@ void GameListWidget::onListViewContextMenuRequested(const QPoint& point)
|
||||
void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
|
||||
{
|
||||
QMenu menu;
|
||||
QHeaderView* header = m_table_view->horizontalHeader();
|
||||
if (!header)
|
||||
return;
|
||||
|
||||
int column_visual = 0;
|
||||
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)
|
||||
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->setChecked(!m_table_view->isColumnHidden(column));
|
||||
connect(action, &QAction::toggled, [this, column](bool enabled) {
|
||||
m_table_view->setColumnHidden(column, !enabled);
|
||||
saveTableViewColumnVisibilitySettings(column);
|
||||
action->setChecked(!m_table_view->isColumnHidden(column_visual));
|
||||
connect(action, &QAction::toggled, [this, column_visual](bool enabled) {
|
||||
m_table_view->setColumnHidden(column_visual, !enabled);
|
||||
onTableHeaderStateChanged();
|
||||
resizeTableViewColumnsToFit();
|
||||
});
|
||||
}
|
||||
@ -697,91 +733,100 @@ bool GameListWidget::event(QEvent* event)
|
||||
void GameListWidget::resizeTableViewColumnsToFit()
|
||||
{
|
||||
QtUtils::ResizeColumnsForTableView(m_table_view, {
|
||||
55, // type
|
||||
85, // code
|
||||
-1, // title
|
||||
-1, // file title
|
||||
75, // crc
|
||||
95, // time played
|
||||
90, // last played
|
||||
80, // size
|
||||
60, // region
|
||||
120, // compatibility
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Type],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Serial],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_FileTitle],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Type],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_CRC],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_TimePlayed],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_LastPlayed],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Size],
|
||||
DEFAULT_COLUMN_WIDTHS[GameListModel::Column_Region],
|
||||
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)));
|
||||
}
|
||||
|
||||
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();
|
||||
Host::SetBaseBoolSettingValue("GameListTableView", "SortDescending", static_cast<bool>(sort_order));
|
||||
}
|
||||
|
||||
std::optional<GameList::Entry> GameListWidget::getSelectedEntry() const
|
||||
|
||||
@ -85,6 +85,7 @@ private Q_SLOTS:
|
||||
void onListViewItemActivated(const QModelIndex& index);
|
||||
void onListViewContextMenuRequested(const QPoint& point);
|
||||
void onCoverScaleChanged();
|
||||
void onTableHeaderStateChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
void showGameList();
|
||||
@ -102,11 +103,10 @@ protected:
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
private:
|
||||
void loadTableViewColumnVisibilitySettings();
|
||||
void saveTableViewColumnVisibilitySettings();
|
||||
void saveTableViewColumnVisibilitySettings(int column);
|
||||
void loadTableViewColumnSortSettings();
|
||||
void saveTableViewColumnSortSettings(const int sort_column, const Qt::SortOrder sort_order);
|
||||
void loadTableHeaderState();
|
||||
void applyTableHeaderDefaults();
|
||||
void resetTableHeaderToDefault();
|
||||
void saveSortSettings(int column, Qt::SortOrder sort_order);
|
||||
void listZoom(float delta);
|
||||
void updateToolbar();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user