mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-12-06 07:12:28 +01:00
Merge branch 'master' into rsx_capture
This commit is contained in:
commit
a02c503536
|
|
@ -8,11 +8,12 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
|
||||||
### Windows 10 or later
|
### Windows 10 or later
|
||||||
|
|
||||||
The following tools are required to build RPCS3 on Windows 10 or later:
|
The following tools are required to build RPCS3 on Windows 10 or later:
|
||||||
- [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
|
- [Visual Studio 2022/2026](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
|
||||||
- **Optional** - [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
|
- **Optional** - [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
|
||||||
|
|
||||||
**NOTES:**
|
**NOTES:**
|
||||||
- **Visual Studio 2022** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`).
|
- **Visual Studio 2026** needs at least **CMake 4.2.0+**.
|
||||||
|
- **Visual Studio 2022/2026** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`).
|
||||||
See sections [Building with Visual Studio sln solution](#building-with-visual-studio-sln-solution) and [Building with Visual Studio CMake solution](#building-with-visual-studio-cmake-solution)
|
See sections [Building with Visual Studio sln solution](#building-with-visual-studio-sln-solution) and [Building with Visual Studio CMake solution](#building-with-visual-studio-cmake-solution)
|
||||||
on how to build the project with **Visual Studio**.
|
on how to build the project with **Visual Studio**.
|
||||||
- Install and use this standalone **CMake** tool just in case of your preference. See section [Building with standalone CMake tool](#building-with-standalone-cmake-tool) on how to build the project
|
- Install and use this standalone **CMake** tool just in case of your preference. See section [Building with standalone CMake tool](#building-with-standalone-cmake-tool) on how to build the project
|
||||||
|
|
|
||||||
|
|
@ -720,9 +720,19 @@ void spu_cache::initialize(bool build_existing_cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPU cache file (version + block size type)
|
// SPU cache file (version + block size type)
|
||||||
const std::string loc = ppu_cache + "spu-" + fmt::to_lower(g_cfg.core.spu_block_size.to_string()) + "-v1-tane.dat";
|
const std::string filename = "spu-" + fmt::to_lower(g_cfg.core.spu_block_size.to_string()) + "-v1-tane.dat";
|
||||||
|
const std::string loc = ppu_cache + filename;
|
||||||
|
const std::string loc_debug = fs::get_cache_dir() + "DEBUG/" + filename;
|
||||||
|
|
||||||
spu_cache cache(loc);
|
bool is_debug = false;
|
||||||
|
|
||||||
|
if (fs::is_file(loc_debug))
|
||||||
|
{
|
||||||
|
spu_log.success("SPU Cache override applied!");
|
||||||
|
is_debug = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
spu_cache cache(is_debug ? loc_debug : loc);
|
||||||
|
|
||||||
if (!cache)
|
if (!cache)
|
||||||
{
|
{
|
||||||
|
|
@ -4963,6 +4973,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||||
u32 lsa_last_pc = SPU_LS_SIZE; // PC of first LSA write
|
u32 lsa_last_pc = SPU_LS_SIZE; // PC of first LSA write
|
||||||
u32 get_pc = SPU_LS_SIZE; // PC of GETLLAR
|
u32 get_pc = SPU_LS_SIZE; // PC of GETLLAR
|
||||||
u32 put_pc = SPU_LS_SIZE; // PC of PUTLLC
|
u32 put_pc = SPU_LS_SIZE; // PC of PUTLLC
|
||||||
|
u32 rdatomic_pc = SPU_LS_SIZE; // PC of last RdAtomcStat read
|
||||||
reg_state_t ls{}; // state of LS load/store address register
|
reg_state_t ls{}; // state of LS load/store address register
|
||||||
reg_state_t ls_offs = reg_state_t::from_value(0); // Added value to ls
|
reg_state_t ls_offs = reg_state_t::from_value(0); // Added value to ls
|
||||||
reg_state_t lsa{}; // state of LSA register on GETLLAR
|
reg_state_t lsa{}; // state of LSA register on GETLLAR
|
||||||
|
|
@ -5008,7 +5019,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||||
ls_invalid = true;
|
ls_invalid = true;
|
||||||
ls_write |= write;
|
ls_write |= write;
|
||||||
|
|
||||||
if (write)
|
if (ls_write)
|
||||||
{
|
{
|
||||||
return discard();
|
return discard();
|
||||||
}
|
}
|
||||||
|
|
@ -6323,6 +6334,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atomic16->rdatomic_pc = pos;
|
||||||
|
|
||||||
const auto it = atomic16_all.find(pos);
|
const auto it = atomic16_all.find(pos);
|
||||||
|
|
||||||
if (it == atomic16_all.end())
|
if (it == atomic16_all.end())
|
||||||
|
|
@ -7263,7 +7276,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||||
|
|
||||||
for (const auto& [pc_commited, pattern] : atomic16_all)
|
for (const auto& [pc_commited, pattern] : atomic16_all)
|
||||||
{
|
{
|
||||||
if (!pattern.active)
|
if (!pattern.active || pattern.lsa_pc >= pattern.rdatomic_pc)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -7273,6 +7286,17 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string pattern_hash;
|
||||||
|
{
|
||||||
|
sha1_context ctx;
|
||||||
|
u8 output[20]{};
|
||||||
|
|
||||||
|
sha1_starts(&ctx);
|
||||||
|
sha1_update(&ctx, reinterpret_cast<const u8*>(result.data.data()) + (pattern.lsa_pc - result.lower_bound), pattern.rdatomic_pc - pattern.lsa_pc);
|
||||||
|
sha1_finish(&ctx, output);
|
||||||
|
fmt::append(pattern_hash, "%s", fmt::base57(output));
|
||||||
|
}
|
||||||
|
|
||||||
union putllc16_or_0_info
|
union putllc16_or_0_info
|
||||||
{
|
{
|
||||||
u64 data;
|
u64 data;
|
||||||
|
|
@ -7295,8 +7319,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||||
value.required_pc = pattern.required_pc;
|
value.required_pc = pattern.required_pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
spu_log.success("PUTLLC0 Pattern Detected! (put_pc=0x%x, %s) (putllc0=%d, putllc16+0=%d, all=%d)", pattern.put_pc, func_hash, ++stats.nowrite, ++stats.single, +stats.all);
|
// spu_log.success("PUTLLC0 Pattern Detected! (put_pc=0x%x, %s) (putllc0=%d, putllc16+0=%d, all=%d)", pattern.put_pc, func_hash, ++stats.nowrite, ++stats.single, +stats.all);
|
||||||
add_pattern(false, inst_attr::putllc0, pattern.put_pc - lsa, value.data);
|
// add_pattern(false, inst_attr::putllc0, pattern.put_pc - lsa, value.data);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7363,16 +7387,35 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||||
value.reg2 = pattern.reg2;
|
value.reg2 = pattern.reg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool allow_pattern = true;
|
||||||
|
|
||||||
if (g_cfg.core.spu_accurate_reservations)
|
if (g_cfg.core.spu_accurate_reservations)
|
||||||
{
|
{
|
||||||
// Because enabling it is a hack, as it turns out
|
// The problem with PUTLLC16 optimization, that it is in theory correct at the bounds of the spu function.
|
||||||
// continue;
|
// But if the SPU code reuses the cache line data observed, it is not truly atomic.
|
||||||
|
// So we may enable it only for known cases where SPU atomic data is not used after the function leaves.
|
||||||
|
|
||||||
|
// So the two options are:
|
||||||
|
|
||||||
|
// 1. Atomic compare exchange 16 bytes operation. (rest of data is not read) -> good for RPCS3 to optimize.
|
||||||
|
// 2. Fetch 128 bytes (read them later), modify only 16 bytes. -> Bad for RPCS3 to optimize.
|
||||||
|
|
||||||
|
// This difference cannot be known at analyzer time but from observing callers.
|
||||||
|
static constexpr std::initializer_list<std::string_view> allowed_patterns =
|
||||||
|
{
|
||||||
|
"620oYSe8uQqq9eTkhWfMqoEXX0us"sv, // CellSpurs JobChain acquire pattern
|
||||||
|
};
|
||||||
|
|
||||||
|
allow_pattern = std::any_of(allowed_patterns.begin(), allowed_patterns.end(), FN(pattern_hash == x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allow_pattern)
|
||||||
|
{
|
||||||
add_pattern(false, inst_attr::putllc16, pattern.put_pc - result.entry_point, value.data);
|
add_pattern(false, inst_attr::putllc16, pattern.put_pc - result.entry_point, value.data);
|
||||||
|
}
|
||||||
|
|
||||||
spu_log.success("PUTLLC16 Pattern Detected! (mem_count=%d, put_pc=0x%x, pc_rel=%d, offset=0x%x, const=%u, two_regs=%d, reg=%u, runtime=%d, 0x%x-%s) (putllc0=%d, putllc16+0=%d, all=%d)"
|
spu_log.success("PUTLLC16 Pattern Detected! (mem_count=%d, put_pc=0x%x, pc_rel=%d, offset=0x%x, const=%u, two_regs=%d, reg=%u, runtime=%d, 0x%x-%s, pattern-hash=%s) (putllc0=%d, putllc16+0=%d, all=%d)"
|
||||||
, pattern.mem_count, pattern.put_pc, value.type == v_relative, value.off18, value.type == v_const, value.type == v_reg2, value.reg, value.runtime16_select, entry_point, func_hash, +stats.nowrite, ++stats.single, +stats.all);
|
, pattern.mem_count, pattern.put_pc, value.type == v_relative, value.off18, value.type == v_const, value.type == v_reg2, value.reg, value.runtime16_select, entry_point, func_hash, pattern_hash, +stats.nowrite, ++stats.single, +stats.all);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& [read_pc, pattern] : rchcnt_loop_all)
|
for (const auto& [read_pc, pattern] : rchcnt_loop_all)
|
||||||
|
|
|
||||||
|
|
@ -668,10 +668,9 @@ void emu_settings::EnhanceSpinBox(QSpinBox* spinbox, emu_settings_type type, con
|
||||||
spinbox->setRange(min, max);
|
spinbox->setRange(min, max);
|
||||||
spinbox->setValue(val);
|
spinbox->setValue(val);
|
||||||
|
|
||||||
connect(spinbox, &QSpinBox::textChanged, this, [type, spinbox, this](const QString& /* text*/)
|
connect(spinbox, &QSpinBox::valueChanged, this, [type, this](int value)
|
||||||
{
|
{
|
||||||
if (!spinbox) return;
|
SetSetting(type, fmt::format("%d", value));
|
||||||
SetSetting(type, spinbox->cleanText().toStdString());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(this, &emu_settings::RestoreDefaultsSignal, spinbox, [def, spinbox]()
|
connect(this, &emu_settings::RestoreDefaultsSignal, spinbox, [def, spinbox]()
|
||||||
|
|
@ -724,10 +723,9 @@ void emu_settings::EnhanceDoubleSpinBox(QDoubleSpinBox* spinbox, emu_settings_ty
|
||||||
spinbox->setRange(min, max);
|
spinbox->setRange(min, max);
|
||||||
spinbox->setValue(val);
|
spinbox->setValue(val);
|
||||||
|
|
||||||
connect(spinbox, &QDoubleSpinBox::textChanged, this, [type, spinbox, this](const QString& /* text*/)
|
connect(spinbox, &QDoubleSpinBox::valueChanged, this, [type, this](double value)
|
||||||
{
|
{
|
||||||
if (!spinbox) return;
|
SetSetting(type, fmt::format("%f", value));
|
||||||
SetSetting(type, spinbox->cleanText().toStdString());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(this, &emu_settings::RestoreDefaultsSignal, spinbox, [def, spinbox]()
|
connect(this, &emu_settings::RestoreDefaultsSignal, spinbox, [def, spinbox]()
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,16 @@ game_list::game_list() : QTableWidget(), game_list_base()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_list::sync_header_actions(QList<QAction*>& actions, std::function<bool(int)> get_visibility)
|
void game_list::sync_header_actions(std::map<int, QAction*>& actions, std::function<bool(int)> get_visibility)
|
||||||
{
|
{
|
||||||
ensure(get_visibility);
|
ensure(get_visibility);
|
||||||
|
|
||||||
bool is_dirty = false;
|
bool is_dirty = false;
|
||||||
|
|
||||||
for (int col = 0; col < actions.count(); ++col)
|
for (auto& [col, action] : actions)
|
||||||
{
|
{
|
||||||
const bool is_hidden = !get_visibility(col);
|
const bool is_hidden = !get_visibility(col);
|
||||||
actions[col]->setChecked(!is_hidden);
|
action->setChecked(!is_hidden);
|
||||||
|
|
||||||
if (isColumnHidden(col) != is_hidden)
|
if (isColumnHidden(col) != is_hidden)
|
||||||
{
|
{
|
||||||
|
|
@ -38,7 +38,7 @@ void game_list::sync_header_actions(QList<QAction*>& actions, std::function<bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_list::create_header_actions(QList<QAction*>& actions, std::function<bool(int)> get_visibility, std::function<void(int, bool)> set_visibility)
|
void game_list::create_header_actions(std::map<int, QAction*>& actions, std::function<bool(int)> get_visibility, std::function<void(int, bool)> set_visibility)
|
||||||
{
|
{
|
||||||
ensure(get_visibility);
|
ensure(get_visibility);
|
||||||
ensure(set_visibility);
|
ensure(set_visibility);
|
||||||
|
|
@ -48,27 +48,30 @@ void game_list::create_header_actions(QList<QAction*>& actions, std::function<bo
|
||||||
connect(horizontalHeader(), &QHeaderView::customContextMenuRequested, this, [this, &actions](const QPoint& pos)
|
connect(horizontalHeader(), &QHeaderView::customContextMenuRequested, this, [this, &actions](const QPoint& pos)
|
||||||
{
|
{
|
||||||
QMenu* configure = new QMenu(this);
|
QMenu* configure = new QMenu(this);
|
||||||
configure->addActions(actions);
|
for (auto& [col, action] : actions)
|
||||||
|
{
|
||||||
|
configure->addAction(action);
|
||||||
|
}
|
||||||
configure->exec(horizontalHeader()->viewport()->mapToGlobal(pos));
|
configure->exec(horizontalHeader()->viewport()->mapToGlobal(pos));
|
||||||
});
|
});
|
||||||
|
|
||||||
for (int col = 0; col < actions.count(); ++col)
|
for (auto& [col, action] : actions)
|
||||||
{
|
{
|
||||||
actions[col]->setCheckable(true);
|
action->setCheckable(true);
|
||||||
|
|
||||||
connect(actions[col], &QAction::triggered, this, [this, &actions, get_visibility, set_visibility, col](bool checked)
|
connect(action, &QAction::triggered, this, [this, &actions, get_visibility, set_visibility, col](bool checked)
|
||||||
{
|
{
|
||||||
if (!checked) // be sure to have at least one column left so you can call the context menu at all time
|
if (!checked) // be sure to have at least one column left so you can call the context menu at all time
|
||||||
{
|
{
|
||||||
int c = 0;
|
int c = 0;
|
||||||
for (int i = 0; i < actions.count(); ++i)
|
for (auto& [col, action] : actions)
|
||||||
{
|
{
|
||||||
if (get_visibility(i) && ++c > 1)
|
if (get_visibility(col) && ++c > 1)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c < 2)
|
if (c < 2)
|
||||||
{
|
{
|
||||||
actions[col]->setChecked(true); // re-enable the checkbox if we don't change the actual state
|
::at32(actions, col)->setChecked(true); // re-enable the checkbox if we don't change the actual state
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ class game_list : public QTableWidget, public game_list_base
|
||||||
public:
|
public:
|
||||||
game_list();
|
game_list();
|
||||||
|
|
||||||
void sync_header_actions(QList<QAction*>& actions, std::function<bool(int)> get_visibility);
|
void sync_header_actions(std::map<int, QAction*>& actions, std::function<bool(int)> get_visibility);
|
||||||
void create_header_actions(QList<QAction*>& actions, std::function<bool(int)> get_visibility, std::function<void(int, bool)> set_visibility);
|
void create_header_actions(std::map<int, QAction*>& actions, std::function<bool(int)> get_visibility, std::function<void(int, bool)> set_visibility);
|
||||||
|
|
||||||
void clear_list() override; // Use this instead of clearContents
|
void clear_list() override; // Use this instead of clearContents
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,27 +100,28 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> gui_settings, std
|
||||||
m_game_dock->setCentralWidget(m_central_widget);
|
m_game_dock->setCentralWidget(m_central_widget);
|
||||||
|
|
||||||
// Actions regarding showing/hiding columns
|
// Actions regarding showing/hiding columns
|
||||||
auto add_column = [this](gui::game_list_columns col, const QString& header_text, const QString& action_text)
|
const auto add_column = [this](gui::game_list_columns col)
|
||||||
{
|
{
|
||||||
m_game_list->setHorizontalHeaderItem(static_cast<int>(col), new QTableWidgetItem(header_text));
|
const int column = static_cast<int>(col);
|
||||||
m_columnActs.append(new QAction(action_text, this));
|
m_game_list->setHorizontalHeaderItem(column, new QTableWidgetItem(get_header_text(column)));
|
||||||
|
m_column_acts[column] = new QAction(get_action_text(column), this);
|
||||||
};
|
};
|
||||||
|
|
||||||
add_column(gui::game_list_columns::icon, tr("Icon"), tr("Show Icons"));
|
add_column(gui::game_list_columns::icon);
|
||||||
add_column(gui::game_list_columns::name, tr("Name"), tr("Show Names"));
|
add_column(gui::game_list_columns::name);
|
||||||
add_column(gui::game_list_columns::serial, tr("Serial"), tr("Show Serials"));
|
add_column(gui::game_list_columns::serial);
|
||||||
add_column(gui::game_list_columns::firmware, tr("Firmware"), tr("Show Firmwares"));
|
add_column(gui::game_list_columns::firmware);
|
||||||
add_column(gui::game_list_columns::version, tr("Version"), tr("Show Versions"));
|
add_column(gui::game_list_columns::version);
|
||||||
add_column(gui::game_list_columns::category, tr("Category"), tr("Show Categories"));
|
add_column(gui::game_list_columns::category);
|
||||||
add_column(gui::game_list_columns::path, tr("Path"), tr("Show Paths"));
|
add_column(gui::game_list_columns::path);
|
||||||
add_column(gui::game_list_columns::move, tr("PlayStation Move"), tr("Show PlayStation Move"));
|
add_column(gui::game_list_columns::move);
|
||||||
add_column(gui::game_list_columns::resolution, tr("Supported Resolutions"), tr("Show Supported Resolutions"));
|
add_column(gui::game_list_columns::resolution);
|
||||||
add_column(gui::game_list_columns::sound, tr("Sound Formats"), tr("Show Sound Formats"));
|
add_column(gui::game_list_columns::sound);
|
||||||
add_column(gui::game_list_columns::parental, tr("Parental Level"), tr("Show Parental Levels"));
|
add_column(gui::game_list_columns::parental);
|
||||||
add_column(gui::game_list_columns::last_play, tr("Last Played"), tr("Show Last Played"));
|
add_column(gui::game_list_columns::last_play);
|
||||||
add_column(gui::game_list_columns::playtime, tr("Time Played"), tr("Show Time Played"));
|
add_column(gui::game_list_columns::playtime);
|
||||||
add_column(gui::game_list_columns::compat, tr("Compatibility"), tr("Show Compatibility"));
|
add_column(gui::game_list_columns::compat);
|
||||||
add_column(gui::game_list_columns::dir_size, tr("Space On Disk"), tr("Show Space On Disk"));
|
add_column(gui::game_list_columns::dir_size);
|
||||||
|
|
||||||
m_progress_dialog = new progress_dialog(tr("Loading games"), tr("Loading games, please wait..."), tr("Cancel"), 0, 0, false, this, Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
|
m_progress_dialog = new progress_dialog(tr("Loading games"), tr("Loading games, please wait..."), tr("Cancel"), 0, 0, false, this, Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
|
||||||
m_progress_dialog->setMinimumDuration(200); // Only show the progress dialog after some time has passed
|
m_progress_dialog->setMinimumDuration(200); // Only show the progress dialog after some time has passed
|
||||||
|
|
@ -211,7 +212,7 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> gui_settings, std
|
||||||
connect(m_game_list, &game_list::FocusToSearchBar, this, &game_list_frame::FocusToSearchBar);
|
connect(m_game_list, &game_list::FocusToSearchBar, this, &game_list_frame::FocusToSearchBar);
|
||||||
connect(m_game_grid, &game_list_grid::FocusToSearchBar, this, &game_list_frame::FocusToSearchBar);
|
connect(m_game_grid, &game_list_grid::FocusToSearchBar, this, &game_list_frame::FocusToSearchBar);
|
||||||
|
|
||||||
m_game_list->create_header_actions(m_columnActs,
|
m_game_list->create_header_actions(m_column_acts,
|
||||||
[this](int col) { return m_gui_settings->GetGamelistColVisibility(static_cast<gui::game_list_columns>(col)); },
|
[this](int col) { return m_gui_settings->GetGamelistColVisibility(static_cast<gui::game_list_columns>(col)); },
|
||||||
[this](int col, bool visible) { m_gui_settings->SetGamelistColVisibility(static_cast<gui::game_list_columns>(col), visible); });
|
[this](int col, bool visible) { m_gui_settings->SetGamelistColVisibility(static_cast<gui::game_list_columns>(col), visible); });
|
||||||
}
|
}
|
||||||
|
|
@ -227,7 +228,7 @@ void game_list_frame::LoadSettings()
|
||||||
m_show_custom_icons = m_gui_settings->GetValue(gui::gl_custom_icon).toBool();
|
m_show_custom_icons = m_gui_settings->GetValue(gui::gl_custom_icon).toBool();
|
||||||
m_play_hover_movies = m_gui_settings->GetValue(gui::gl_hover_gifs).toBool();
|
m_play_hover_movies = m_gui_settings->GetValue(gui::gl_hover_gifs).toBool();
|
||||||
|
|
||||||
m_game_list->sync_header_actions(m_columnActs, [this](int col) { return m_gui_settings->GetGamelistColVisibility(static_cast<gui::game_list_columns>(col)); });
|
m_game_list->sync_header_actions(m_column_acts, [this](int col) { return m_gui_settings->GetGamelistColVisibility(static_cast<gui::game_list_columns>(col)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
game_list_frame::~game_list_frame()
|
game_list_frame::~game_list_frame()
|
||||||
|
|
@ -238,6 +239,54 @@ game_list_frame::~game_list_frame()
|
||||||
gui::utils::stop_future_watcher(m_refresh_watcher, true);
|
gui::utils::stop_future_watcher(m_refresh_watcher, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString game_list_frame::get_header_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<gui::game_list_columns>(col))
|
||||||
|
{
|
||||||
|
case gui::game_list_columns::icon: return tr("Icon");
|
||||||
|
case gui::game_list_columns::name: return tr("Name");
|
||||||
|
case gui::game_list_columns::serial: return tr("Serial");
|
||||||
|
case gui::game_list_columns::firmware: return tr("Firmware");
|
||||||
|
case gui::game_list_columns::version: return tr("Version");
|
||||||
|
case gui::game_list_columns::category: return tr("Category");
|
||||||
|
case gui::game_list_columns::path: return tr("Path");
|
||||||
|
case gui::game_list_columns::move: return tr("PlayStation Move");
|
||||||
|
case gui::game_list_columns::resolution: return tr("Supported Resolutions");
|
||||||
|
case gui::game_list_columns::sound: return tr("Sound Formats");
|
||||||
|
case gui::game_list_columns::parental: return tr("Parental Level");
|
||||||
|
case gui::game_list_columns::last_play: return tr("Last Played");
|
||||||
|
case gui::game_list_columns::playtime: return tr("Time Played");
|
||||||
|
case gui::game_list_columns::compat: return tr("Compatibility");
|
||||||
|
case gui::game_list_columns::dir_size: return tr("Space On Disk");
|
||||||
|
case gui::game_list_columns::count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString game_list_frame::get_action_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<gui::game_list_columns>(col))
|
||||||
|
{
|
||||||
|
case gui::game_list_columns::icon: return tr("Show Icons");
|
||||||
|
case gui::game_list_columns::name: return tr("Show Names");
|
||||||
|
case gui::game_list_columns::serial: return tr("Show Serials");
|
||||||
|
case gui::game_list_columns::firmware: return tr("Show Firmwares");
|
||||||
|
case gui::game_list_columns::version: return tr("Show Versions");
|
||||||
|
case gui::game_list_columns::category: return tr("Show Categories");
|
||||||
|
case gui::game_list_columns::path: return tr("Show Paths");
|
||||||
|
case gui::game_list_columns::move: return tr("Show PlayStation Move");
|
||||||
|
case gui::game_list_columns::resolution: return tr("Show Supported Resolutions");
|
||||||
|
case gui::game_list_columns::sound: return tr("Show Sound Formats");
|
||||||
|
case gui::game_list_columns::parental: return tr("Show Parental Levels");
|
||||||
|
case gui::game_list_columns::last_play: return tr("Show Last Played");
|
||||||
|
case gui::game_list_columns::playtime: return tr("Show Time Played");
|
||||||
|
case gui::game_list_columns::compat: return tr("Show Compatibility");
|
||||||
|
case gui::game_list_columns::dir_size: return tr("Show Space On Disk");
|
||||||
|
case gui::game_list_columns::count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void game_list_frame::OnColClicked(int col)
|
void game_list_frame::OnColClicked(int col)
|
||||||
{
|
{
|
||||||
if (col == static_cast<int>(gui::game_list_columns::icon)) return; // Don't "sort" icons.
|
if (col == static_cast<int>(gui::game_list_columns::icon)) return; // Don't "sort" icons.
|
||||||
|
|
@ -417,6 +466,21 @@ void game_list_frame::Refresh(const bool from_drive, const std::vector<std::stri
|
||||||
m_progress_dialog->SetValue(0);
|
m_progress_dialog->SetValue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update headers
|
||||||
|
for (int col = 0; col < m_game_list->horizontalHeader()->count(); col++)
|
||||||
|
{
|
||||||
|
if (auto item = m_game_list->horizontalHeaderItem(col))
|
||||||
|
{
|
||||||
|
item->setText(get_header_text(col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update actions
|
||||||
|
for (auto& [col, action] : m_column_acts)
|
||||||
|
{
|
||||||
|
action->setText(get_action_text(col));
|
||||||
|
}
|
||||||
|
|
||||||
const std::string games_dir = rpcs3::utils::get_games_dir();
|
const std::string games_dir = rpcs3::utils::get_games_dir();
|
||||||
|
|
||||||
// Remove the specified and detected serials (title id) belonging to "games_dir" folder only from the game list in memory
|
// Remove the specified and detected serials (title id) belonging to "games_dir" folder only from the game list in memory
|
||||||
|
|
@ -920,7 +984,7 @@ void game_list_frame::OnRefreshFinished()
|
||||||
if (!std::exchange(m_initial_refresh_done, true))
|
if (!std::exchange(m_initial_refresh_done, true))
|
||||||
{
|
{
|
||||||
m_game_list->restore_layout(m_gui_settings->GetValue(gui::gl_state).toByteArray());
|
m_game_list->restore_layout(m_gui_settings->GetValue(gui::gl_state).toByteArray());
|
||||||
m_game_list->sync_header_actions(m_columnActs, [this](int col) { return m_gui_settings->GetGamelistColVisibility(static_cast<gui::game_list_columns>(col)); });
|
m_game_list->sync_header_actions(m_column_acts, [this](int col) { return m_gui_settings->GetGamelistColVisibility(static_cast<gui::game_list_columns>(col)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit signal and remove slots
|
// Emit signal and remove slots
|
||||||
|
|
@ -959,9 +1023,9 @@ void game_list_frame::ToggleCategoryFilter(const QStringList& categories, bool s
|
||||||
|
|
||||||
void game_list_frame::SaveSettings()
|
void game_list_frame::SaveSettings()
|
||||||
{
|
{
|
||||||
for (int col = 0; col < m_columnActs.count(); ++col)
|
for (const auto& [col, action] : m_column_acts)
|
||||||
{
|
{
|
||||||
m_gui_settings->SetGamelistColVisibility(static_cast<gui::game_list_columns>(col), m_columnActs[col]->isChecked());
|
m_gui_settings->SetGamelistColVisibility(static_cast<gui::game_list_columns>(col), action->isChecked());
|
||||||
}
|
}
|
||||||
m_gui_settings->SetValue(gui::gl_sortCol, m_sort_column, false);
|
m_gui_settings->SetValue(gui::gl_sortCol, m_sort_column, false);
|
||||||
m_gui_settings->SetValue(gui::gl_sortAsc, m_col_sort_order == Qt::AscendingOrder, false);
|
m_gui_settings->SetValue(gui::gl_sortAsc, m_col_sort_order == Qt::AscendingOrder, false);
|
||||||
|
|
@ -1121,7 +1185,7 @@ void game_list_frame::CreateShortcuts(const std::vector<game_info>& games, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_list_frame::ShowContextMenu(const QPoint &pos)
|
void game_list_frame::ShowContextMenu(const QPoint& pos)
|
||||||
{
|
{
|
||||||
QPoint global_pos;
|
QPoint global_pos;
|
||||||
game_info gameinfo;
|
game_info gameinfo;
|
||||||
|
|
@ -2704,7 +2768,7 @@ void game_list_frame::ShowCustomConfigIcon(const game_info& game)
|
||||||
RepaintIcons();
|
RepaintIcons();
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_list_frame::ResizeIcons(const int& slider_pos)
|
void game_list_frame::ResizeIcons(int slider_pos)
|
||||||
{
|
{
|
||||||
m_icon_size_index = slider_pos;
|
m_icon_size_index = slider_pos;
|
||||||
m_icon_size = gui_settings::SizeFromSlider(slider_pos);
|
m_icon_size = gui_settings::SizeFromSlider(slider_pos);
|
||||||
|
|
@ -2712,7 +2776,7 @@ void game_list_frame::ResizeIcons(const int& slider_pos)
|
||||||
RepaintIcons();
|
RepaintIcons();
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_list_frame::RepaintIcons(const bool& from_settings)
|
void game_list_frame::RepaintIcons(bool from_settings)
|
||||||
{
|
{
|
||||||
gui::utils::stop_future_watcher(m_parsing_watcher, false);
|
gui::utils::stop_future_watcher(m_parsing_watcher, false);
|
||||||
gui::utils::stop_future_watcher(m_refresh_watcher, false);
|
gui::utils::stop_future_watcher(m_refresh_watcher, false);
|
||||||
|
|
@ -2746,7 +2810,7 @@ void game_list_frame::SetShowHidden(bool show)
|
||||||
m_show_hidden = show;
|
m_show_hidden = show;
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_list_frame::SetListMode(const bool& is_list)
|
void game_list_frame::SetListMode(bool is_list)
|
||||||
{
|
{
|
||||||
m_old_layout_is_list = m_is_list_layout;
|
m_old_layout_is_list = m_is_list_layout;
|
||||||
m_is_list_layout = is_list;
|
m_is_list_layout = is_list;
|
||||||
|
|
|
||||||
|
|
@ -48,10 +48,10 @@ public:
|
||||||
void SaveSettings();
|
void SaveSettings();
|
||||||
|
|
||||||
/** Resize Gamelist Icons to size given by slider position */
|
/** Resize Gamelist Icons to size given by slider position */
|
||||||
void ResizeIcons(const int& slider_pos);
|
void ResizeIcons(int slider_pos);
|
||||||
|
|
||||||
/** Repaint Gamelist Icons with new background color */
|
/** Repaint Gamelist Icons with new background color */
|
||||||
void RepaintIcons(const bool& from_settings = false);
|
void RepaintIcons(bool from_settings = false);
|
||||||
|
|
||||||
void SetShowHidden(bool show);
|
void SetShowHidden(bool show);
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ public Q_SLOTS:
|
||||||
void BatchRemoveCustomConfigurations();
|
void BatchRemoveCustomConfigurations();
|
||||||
void BatchRemoveCustomPadConfigurations();
|
void BatchRemoveCustomPadConfigurations();
|
||||||
void BatchRemoveShaderCaches();
|
void BatchRemoveShaderCaches();
|
||||||
void SetListMode(const bool& is_list);
|
void SetListMode(bool is_list);
|
||||||
void SetSearchText(const QString& text);
|
void SetSearchText(const QString& text);
|
||||||
void SetShowCompatibilityInGrid(bool show);
|
void SetShowCompatibilityInGrid(bool show);
|
||||||
void SetPreferGameDataIcons(bool enabled);
|
void SetPreferGameDataIcons(bool enabled);
|
||||||
|
|
@ -83,7 +83,7 @@ private Q_SLOTS:
|
||||||
void OnRefreshFinished();
|
void OnRefreshFinished();
|
||||||
void OnCompatFinished();
|
void OnCompatFinished();
|
||||||
void OnColClicked(int col);
|
void OnColClicked(int col);
|
||||||
void ShowContextMenu(const QPoint &pos);
|
void ShowContextMenu(const QPoint& pos);
|
||||||
void doubleClickedSlot(QTableWidgetItem* item);
|
void doubleClickedSlot(QTableWidgetItem* item);
|
||||||
void doubleClickedSlot(const game_info& game);
|
void doubleClickedSlot(const game_info& game);
|
||||||
void ItemSelectionChangedSlot();
|
void ItemSelectionChangedSlot();
|
||||||
|
|
@ -91,7 +91,7 @@ Q_SIGNALS:
|
||||||
void GameListFrameClosed();
|
void GameListFrameClosed();
|
||||||
void NotifyGameSelection(const game_info& game);
|
void NotifyGameSelection(const game_info& game);
|
||||||
void RequestBoot(const game_info& game, cfg_mode config_mode = cfg_mode::custom, const std::string& config_path = "", const std::string& savestate = "");
|
void RequestBoot(const game_info& game, cfg_mode config_mode = cfg_mode::custom, const std::string& config_path = "", const std::string& savestate = "");
|
||||||
void RequestIconSizeChange(const int& val);
|
void RequestIconSizeChange(int val);
|
||||||
void NotifyEmuSettingsChange();
|
void NotifyEmuSettingsChange();
|
||||||
void FocusToSearchBar();
|
void FocusToSearchBar();
|
||||||
void Refreshed();
|
void Refreshed();
|
||||||
|
|
@ -127,6 +127,9 @@ protected:
|
||||||
private:
|
private:
|
||||||
void push_path(const std::string& path, std::vector<std::string>& legit_paths);
|
void push_path(const std::string& path, std::vector<std::string>& legit_paths);
|
||||||
|
|
||||||
|
QString get_header_text(int col) const;
|
||||||
|
QString get_action_text(int col) const;
|
||||||
|
|
||||||
void ShowCustomConfigIcon(const game_info& game);
|
void ShowCustomConfigIcon(const game_info& game);
|
||||||
bool SearchMatchesApp(const QString& name, const QString& serial, bool fallback = false) const;
|
bool SearchMatchesApp(const QString& name, const QString& serial, bool fallback = false) const;
|
||||||
|
|
||||||
|
|
@ -165,7 +168,7 @@ private:
|
||||||
game_list_table* m_game_list = nullptr;
|
game_list_table* m_game_list = nullptr;
|
||||||
game_compatibility* m_game_compat = nullptr;
|
game_compatibility* m_game_compat = nullptr;
|
||||||
progress_dialog* m_progress_dialog = nullptr;
|
progress_dialog* m_progress_dialog = nullptr;
|
||||||
QList<QAction*> m_columnActs;
|
std::map<int, QAction*> m_column_acts;
|
||||||
Qt::SortOrder m_col_sort_order{};
|
Qt::SortOrder m_col_sort_order{};
|
||||||
int m_sort_column{};
|
int m_sort_column{};
|
||||||
bool m_initial_refresh_done = false;
|
bool m_initial_refresh_done = false;
|
||||||
|
|
|
||||||
|
|
@ -2344,6 +2344,8 @@ void main_window::RetranslateUI(const QStringList& language_codes, const QString
|
||||||
{
|
{
|
||||||
m_game_list_frame->Refresh(true);
|
m_game_list_frame->Refresh(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Q_EMIT RequestDialogRepaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void main_window::ShowTitleBars(bool show) const
|
void main_window::ShowTitleBars(bool show) const
|
||||||
|
|
@ -3343,7 +3345,7 @@ void main_window::CreateConnects()
|
||||||
connect(ui->showCustomIconsAct, &QAction::triggered, m_game_list_frame, &game_list_frame::SetShowCustomIcons);
|
connect(ui->showCustomIconsAct, &QAction::triggered, m_game_list_frame, &game_list_frame::SetShowCustomIcons);
|
||||||
connect(ui->playHoverGifsAct, &QAction::triggered, m_game_list_frame, &game_list_frame::SetPlayHoverGifs);
|
connect(ui->playHoverGifsAct, &QAction::triggered, m_game_list_frame, &game_list_frame::SetPlayHoverGifs);
|
||||||
|
|
||||||
connect(m_game_list_frame, &game_list_frame::RequestIconSizeChange, this, [this](const int& val)
|
connect(m_game_list_frame, &game_list_frame::RequestIconSizeChange, this, [this](int val)
|
||||||
{
|
{
|
||||||
const int idx = ui->sizeSlider->value() + val;
|
const int idx = ui->sizeSlider->value() + val;
|
||||||
m_save_slider_pos = true;
|
m_save_slider_pos = true;
|
||||||
|
|
|
||||||
|
|
@ -432,9 +432,9 @@ memory_viewer_panel::memory_viewer_panel(QWidget* parent, std::shared_ptr<CPUDis
|
||||||
|
|
||||||
scroll(0); // Refresh
|
scroll(0); // Refresh
|
||||||
});
|
});
|
||||||
connect(sb_words, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [=, this]()
|
connect(sb_words, &QSpinBox::valueChanged, this, [this](int value)
|
||||||
{
|
{
|
||||||
m_colcount = 1 << sb_words->value();
|
m_colcount = 1 << value;
|
||||||
ShowMemory();
|
ShowMemory();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ pad_motion_settings_dialog::pad_motion_settings_dialog(QDialog* parent, std::sha
|
||||||
m_config_entries[i]->mirrored.set(state != Qt::Unchecked);
|
m_config_entries[i]->mirrored.set(state != Qt::Unchecked);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_shifts[i], QOverload<int>::of(&QSpinBox::valueChanged), this, [this, i](int value)
|
connect(m_shifts[i], &QSpinBox::valueChanged, this, [this, i](int value)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(m_config_mutex);
|
std::lock_guard lock(m_config_mutex);
|
||||||
m_config_entries[i]->shift.set(value);
|
m_config_entries[i]->shift.set(value);
|
||||||
|
|
|
||||||
|
|
@ -123,8 +123,8 @@ patch_manager_dialog::patch_manager_dialog(std::shared_ptr<gui_settings> gui_set
|
||||||
handle_config_value_changed(ui->configurable_combo_box->itemData(index).toDouble());
|
handle_config_value_changed(ui->configurable_combo_box->itemData(index).toDouble());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(ui->configurable_spin_box, QOverload<int>::of(&QSpinBox::valueChanged), this, &patch_manager_dialog::handle_config_value_changed);
|
connect(ui->configurable_spin_box, &QSpinBox::valueChanged, this, &patch_manager_dialog::handle_config_value_changed);
|
||||||
connect(ui->configurable_double_spin_box, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &patch_manager_dialog::handle_config_value_changed);
|
connect(ui->configurable_double_spin_box, &QDoubleSpinBox::valueChanged, this, &patch_manager_dialog::handle_config_value_changed);
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close);
|
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close);
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::clicked, [this](QAbstractButton* button)
|
connect(ui->buttonBox, &QDialogButtonBox::clicked, [this](QAbstractButton* button)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ void raw_mouse_settings_dialog::add_tabs(QTabWidget* tabs)
|
||||||
m_accel_spin_boxes.push_back(mouse_acceleration_spin_box);
|
m_accel_spin_boxes.push_back(mouse_acceleration_spin_box);
|
||||||
mouse_acceleration_spin_box->setRange(0.1, 10.0);
|
mouse_acceleration_spin_box->setRange(0.1, 10.0);
|
||||||
mouse_acceleration_spin_box->setValue(config->mouse_acceleration.get() / 100.0);
|
mouse_acceleration_spin_box->setValue(config->mouse_acceleration.get() / 100.0);
|
||||||
connect(mouse_acceleration_spin_box, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, [player](double value)
|
connect(mouse_acceleration_spin_box, &QDoubleSpinBox::valueChanged, this, [player](double value)
|
||||||
{
|
{
|
||||||
auto& config = ::at32(g_cfg_raw_mouse.players, player)->mouse_acceleration;
|
auto& config = ::at32(g_cfg_raw_mouse.players, player)->mouse_acceleration;
|
||||||
config.set(std::clamp(value * 100.0, config.min, config.max));
|
config.set(std::clamp(value * 100.0, config.min, config.max));
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
LOG_CHANNEL(gui_log, "GUI");
|
LOG_CHANNEL(gui_log, "GUI");
|
||||||
|
|
||||||
enum SaveColumns
|
enum class SaveColumns
|
||||||
{
|
{
|
||||||
Icon = 0,
|
Icon = 0,
|
||||||
Name = 1,
|
Name = 1,
|
||||||
|
|
@ -60,30 +60,26 @@ save_manager_dialog::save_manager_dialog(std::shared_ptr<gui_settings> gui_setti
|
||||||
setMinimumSize(QSize(400, 400));
|
setMinimumSize(QSize(400, 400));
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Future proofing. Makes it easier in future if I add ability to change directories
|
|
||||||
*/
|
|
||||||
void save_manager_dialog::Init()
|
|
||||||
{
|
|
||||||
// Table
|
// Table
|
||||||
m_list = new game_list();
|
m_list = new game_list();
|
||||||
m_list->setItemDelegate(new game_list_delegate(m_list));
|
m_list->setItemDelegate(new game_list_delegate(m_list));
|
||||||
m_list->setSelectionMode(QAbstractItemView::SelectionMode::ExtendedSelection);
|
m_list->setSelectionMode(QAbstractItemView::SelectionMode::ExtendedSelection);
|
||||||
m_list->setSelectionBehavior(QAbstractItemView::SelectRows);
|
m_list->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
m_list->setContextMenuPolicy(Qt::CustomContextMenu);
|
m_list->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
m_list->setColumnCount(SaveColumns::Count);
|
m_list->setColumnCount(static_cast<int>(SaveColumns::Count));
|
||||||
m_list->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
m_list->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||||
m_list->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
m_list->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||||
m_list->verticalScrollBar()->setSingleStep(20);
|
m_list->verticalScrollBar()->setSingleStep(20);
|
||||||
m_list->horizontalScrollBar()->setSingleStep(10);
|
m_list->horizontalScrollBar()->setSingleStep(10);
|
||||||
m_list->setHorizontalHeaderLabels(QStringList() << tr("Icon") << tr("Title & Subtitle") << tr("Last Modified") << tr("Save ID") << tr("Notes"));
|
|
||||||
m_list->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
|
m_list->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
|
||||||
m_list->horizontalHeader()->setStretchLastSection(true);
|
m_list->horizontalHeader()->setStretchLastSection(true);
|
||||||
m_list->setMouseTracking(true);
|
m_list->setMouseTracking(true);
|
||||||
|
|
||||||
|
for (int column = 0; column < static_cast<int>(SaveColumns::Count); column++)
|
||||||
|
{
|
||||||
|
m_list->setHorizontalHeaderItem(column, new QTableWidgetItem(get_header_text(column)));
|
||||||
|
}
|
||||||
|
|
||||||
// Bottom bar
|
// Bottom bar
|
||||||
const int icon_size = m_gui_settings->GetValue(gui::sd_icon_size).toInt();
|
const int icon_size = m_gui_settings->GetValue(gui::sd_icon_size).toInt();
|
||||||
m_icon_size = QSize(icon_size, icon_size * 176 / 320);
|
m_icon_size = QSize(icon_size, icon_size * 176 / 320);
|
||||||
|
|
@ -162,7 +158,7 @@ void save_manager_dialog::Init()
|
||||||
connect(m_button_folder, &QAbstractButton::clicked, [this]()
|
connect(m_button_folder, &QAbstractButton::clicked, [this]()
|
||||||
{
|
{
|
||||||
const int idx = m_list->currentRow();
|
const int idx = m_list->currentRow();
|
||||||
QTableWidgetItem* item = m_list->item(idx, SaveColumns::Name);
|
QTableWidgetItem* item = m_list->item(idx, static_cast<int>(SaveColumns::Name));
|
||||||
if (!item)
|
if (!item)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -176,12 +172,12 @@ void save_manager_dialog::Init()
|
||||||
connect(m_list, &QTableWidget::customContextMenuRequested, this, &save_manager_dialog::ShowContextMenu);
|
connect(m_list, &QTableWidget::customContextMenuRequested, this, &save_manager_dialog::ShowContextMenu);
|
||||||
connect(m_list, &QTableWidget::cellChanged, [&](int row, int col)
|
connect(m_list, &QTableWidget::cellChanged, [&](int row, int col)
|
||||||
{
|
{
|
||||||
if (col != SaveColumns::Note)
|
if (col != static_cast<int>(SaveColumns::Note))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QTableWidgetItem* user_item = m_list->item(row, SaveColumns::Name);
|
QTableWidgetItem* user_item = m_list->item(row, static_cast<int>(SaveColumns::Name));
|
||||||
QTableWidgetItem* text_item = m_list->item(row, SaveColumns::Note);
|
QTableWidgetItem* text_item = m_list->item(row, static_cast<int>(SaveColumns::Note));
|
||||||
if (!user_item || !text_item)
|
if (!user_item || !text_item)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -196,7 +192,7 @@ void save_manager_dialog::Init()
|
||||||
connect(m_list, &QTableWidget::itemSelectionChanged, this, &save_manager_dialog::UpdateDetails);
|
connect(m_list, &QTableWidget::itemSelectionChanged, this, &save_manager_dialog::UpdateDetails);
|
||||||
connect(this, &save_manager_dialog::IconReady, this, [this](int index, const QPixmap& pixmap)
|
connect(this, &save_manager_dialog::IconReady, this, [this](int index, const QPixmap& pixmap)
|
||||||
{
|
{
|
||||||
if (movie_item* item = static_cast<movie_item*>(m_list->item(index, SaveColumns::Icon)))
|
if (movie_item* item = static_cast<movie_item*>(m_list->item(index, static_cast<int>(SaveColumns::Icon))))
|
||||||
{
|
{
|
||||||
item->setData(SaveUserRole::PixmapScaled, pixmap);
|
item->setData(SaveUserRole::PixmapScaled, pixmap);
|
||||||
item->image_change_callback();
|
item->image_change_callback();
|
||||||
|
|
@ -205,6 +201,20 @@ void save_manager_dialog::Init()
|
||||||
connect(search_bar, &QLineEdit::textChanged, this, &save_manager_dialog::text_changed);
|
connect(search_bar, &QLineEdit::textChanged, this, &save_manager_dialog::text_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString save_manager_dialog::get_header_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<SaveColumns>(col))
|
||||||
|
{
|
||||||
|
case SaveColumns::Icon: return tr("Icon");
|
||||||
|
case SaveColumns::Name: return tr("Title & Subtitle");
|
||||||
|
case SaveColumns::Time: return tr("Last Modified");
|
||||||
|
case SaveColumns::Dir: return tr("Save ID");
|
||||||
|
case SaveColumns::Note: return tr("Notes");
|
||||||
|
case SaveColumns::Count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This certainly isn't ideal for this code, as it essentially copies cellSaveData. But, I have no other choice without adding public methods to cellSaveData.
|
* This certainly isn't ideal for this code, as it essentially copies cellSaveData. But, I have no other choice without adding public methods to cellSaveData.
|
||||||
*/
|
*/
|
||||||
|
|
@ -300,6 +310,15 @@ void save_manager_dialog::UpdateList()
|
||||||
m_list->clearContents();
|
m_list->clearContents();
|
||||||
m_list->setRowCount(static_cast<int>(m_save_entries.size()));
|
m_list->setRowCount(static_cast<int>(m_save_entries.size()));
|
||||||
|
|
||||||
|
// Update headers
|
||||||
|
for (int col = 0; col < m_list->horizontalHeader()->count(); col++)
|
||||||
|
{
|
||||||
|
if (auto item = m_list->horizontalHeaderItem(col))
|
||||||
|
{
|
||||||
|
item->setText(get_header_text(col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const QVariantMap notes = m_persistent_settings->GetValue(gui::persistent::save_notes).toMap();
|
const QVariantMap notes = m_persistent_settings->GetValue(gui::persistent::save_notes).toMap();
|
||||||
|
|
||||||
if (m_gui_settings->GetValue(gui::m_enableUIColors).toBool())
|
if (m_gui_settings->GetValue(gui::m_enableUIColors).toBool())
|
||||||
|
|
@ -358,20 +377,20 @@ void save_manager_dialog::UpdateList()
|
||||||
icon_item->stop_movie();
|
icon_item->stop_movie();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
m_list->setItem(i, SaveColumns::Icon, icon_item);
|
m_list->setItem(i, static_cast<int>(SaveColumns::Icon), icon_item);
|
||||||
|
|
||||||
custom_table_widget_item* titleItem = new custom_table_widget_item(title);
|
custom_table_widget_item* titleItem = new custom_table_widget_item(title);
|
||||||
titleItem->setData(Qt::UserRole, i); // For sorting to work properly
|
titleItem->setData(Qt::UserRole, i); // For sorting to work properly
|
||||||
titleItem->setFlags(titleItem->flags() & ~Qt::ItemIsEditable);
|
titleItem->setFlags(titleItem->flags() & ~Qt::ItemIsEditable);
|
||||||
m_list->setItem(i, SaveColumns::Name, titleItem);
|
m_list->setItem(i, static_cast<int>(SaveColumns::Name), titleItem);
|
||||||
|
|
||||||
custom_table_widget_item* timeItem = new custom_table_widget_item(gui::utils::format_timestamp(entry.mtime));
|
custom_table_widget_item* timeItem = new custom_table_widget_item(gui::utils::format_timestamp(entry.mtime));
|
||||||
timeItem->setFlags(timeItem->flags() & ~Qt::ItemIsEditable);
|
timeItem->setFlags(timeItem->flags() & ~Qt::ItemIsEditable);
|
||||||
m_list->setItem(i, SaveColumns::Time, timeItem);
|
m_list->setItem(i, static_cast<int>(SaveColumns::Time), timeItem);
|
||||||
|
|
||||||
custom_table_widget_item* dirNameItem = new custom_table_widget_item(dir_name);
|
custom_table_widget_item* dirNameItem = new custom_table_widget_item(dir_name);
|
||||||
dirNameItem->setFlags(dirNameItem->flags() & ~Qt::ItemIsEditable);
|
dirNameItem->setFlags(dirNameItem->flags() & ~Qt::ItemIsEditable);
|
||||||
m_list->setItem(i, SaveColumns::Dir, dirNameItem);
|
m_list->setItem(i, static_cast<int>(SaveColumns::Dir), dirNameItem);
|
||||||
|
|
||||||
custom_table_widget_item* noteItem = new custom_table_widget_item();
|
custom_table_widget_item* noteItem = new custom_table_widget_item();
|
||||||
noteItem->setFlags(noteItem->flags() | Qt::ItemIsEditable);
|
noteItem->setFlags(noteItem->flags() | Qt::ItemIsEditable);
|
||||||
|
|
@ -379,7 +398,7 @@ void save_manager_dialog::UpdateList()
|
||||||
{
|
{
|
||||||
noteItem->setText(notes[dir_name].toString());
|
noteItem->setText(notes[dir_name].toString());
|
||||||
}
|
}
|
||||||
m_list->setItem(i, SaveColumns::Note, noteItem);
|
m_list->setItem(i, static_cast<int>(SaveColumns::Note), noteItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_list->setSortingEnabled(true); // Enable sorting only after using setItem calls
|
m_list->setSortingEnabled(true); // Enable sorting only after using setItem calls
|
||||||
|
|
@ -422,7 +441,7 @@ void save_manager_dialog::UpdateIcons()
|
||||||
|
|
||||||
for (int i = 0; i < m_list->rowCount(); ++i)
|
for (int i = 0; i < m_list->rowCount(); ++i)
|
||||||
{
|
{
|
||||||
if (movie_item* icon_item = static_cast<movie_item*>(m_list->item(i, SaveColumns::Icon)))
|
if (movie_item* icon_item = static_cast<movie_item*>(m_list->item(i, static_cast<int>(SaveColumns::Icon))))
|
||||||
{
|
{
|
||||||
icon_item->setData(SaveUserRole::PixmapScaled, placeholder);
|
icon_item->setData(SaveUserRole::PixmapScaled, placeholder);
|
||||||
icon_item->setData(Qt::DecorationRole, placeholder);
|
icon_item->setData(Qt::DecorationRole, placeholder);
|
||||||
|
|
@ -430,14 +449,14 @@ void save_manager_dialog::UpdateIcons()
|
||||||
}
|
}
|
||||||
|
|
||||||
m_list->resizeRowsToContents();
|
m_list->resizeRowsToContents();
|
||||||
m_list->resizeColumnToContents(SaveColumns::Icon);
|
m_list->resizeColumnToContents(static_cast<int>(SaveColumns::Icon));
|
||||||
|
|
||||||
const s32 language_index = gui_application::get_language_id();
|
const s32 language_index = gui_application::get_language_id();
|
||||||
const std::string localized_icon = fmt::format("ICON0_%02d.PNG", language_index);
|
const std::string localized_icon = fmt::format("ICON0_%02d.PNG", language_index);
|
||||||
|
|
||||||
for (int i = 0; i < m_list->rowCount(); ++i)
|
for (int i = 0; i < m_list->rowCount(); ++i)
|
||||||
{
|
{
|
||||||
if (movie_item* icon_item = static_cast<movie_item*>(m_list->item(i, SaveColumns::Icon)))
|
if (movie_item* icon_item = static_cast<movie_item*>(m_list->item(i, static_cast<int>(SaveColumns::Icon))))
|
||||||
{
|
{
|
||||||
icon_item->set_icon_load_func([this, cancel = icon_item->icon_loading_aborted(), dpr, localized_icon](int index)
|
icon_item->set_icon_load_func([this, cancel = icon_item->icon_loading_aborted(), dpr, localized_icon](int index)
|
||||||
{
|
{
|
||||||
|
|
@ -448,12 +467,12 @@ void save_manager_dialog::UpdateIcons()
|
||||||
|
|
||||||
QPixmap icon;
|
QPixmap icon;
|
||||||
|
|
||||||
if (movie_item* item = static_cast<movie_item*>(m_list->item(index, SaveColumns::Icon)))
|
if (movie_item* item = static_cast<movie_item*>(m_list->item(index, static_cast<int>(SaveColumns::Icon))))
|
||||||
{
|
{
|
||||||
if (!item->data(SaveUserRole::PixmapLoaded).toBool())
|
if (!item->data(SaveUserRole::PixmapLoaded).toBool())
|
||||||
{
|
{
|
||||||
// Load game icon
|
// Load game icon
|
||||||
if (QTableWidgetItem* user_item = m_list->item(index, SaveColumns::Name))
|
if (QTableWidgetItem* user_item = m_list->item(index, static_cast<int>(SaveColumns::Name)))
|
||||||
{
|
{
|
||||||
const int idx_real = user_item->data(Qt::UserRole).toInt();
|
const int idx_real = user_item->data(Qt::UserRole).toInt();
|
||||||
const SaveDataEntry& entry = ::at32(m_save_entries, idx_real);
|
const SaveDataEntry& entry = ::at32(m_save_entries, idx_real);
|
||||||
|
|
@ -534,7 +553,7 @@ void save_manager_dialog::OnSort(int logicalIndex)
|
||||||
// Remove a save file, need to be confirmed.
|
// Remove a save file, need to be confirmed.
|
||||||
void save_manager_dialog::OnEntryRemove(int row, bool user_interaction)
|
void save_manager_dialog::OnEntryRemove(int row, bool user_interaction)
|
||||||
{
|
{
|
||||||
if (QTableWidgetItem* item = m_list->item(row, SaveColumns::Name))
|
if (QTableWidgetItem* item = m_list->item(row, static_cast<int>(SaveColumns::Name)))
|
||||||
{
|
{
|
||||||
const int idx_real = item->data(Qt::UserRole).toInt();
|
const int idx_real = item->data(Qt::UserRole).toInt();
|
||||||
const SaveDataEntry& entry = ::at32(m_save_entries, idx_real);
|
const SaveDataEntry& entry = ::at32(m_save_entries, idx_real);
|
||||||
|
|
@ -599,7 +618,7 @@ void save_manager_dialog::ShowContextMenu(const QPoint& pos)
|
||||||
connect(removeAct, &QAction::triggered, this, &save_manager_dialog::OnEntriesRemove); // entriesremove handles case of one as well
|
connect(removeAct, &QAction::triggered, this, &save_manager_dialog::OnEntriesRemove); // entriesremove handles case of one as well
|
||||||
connect(showDirAct, &QAction::triggered, [this, idx]()
|
connect(showDirAct, &QAction::triggered, [this, idx]()
|
||||||
{
|
{
|
||||||
QTableWidgetItem* item = m_list->item(idx, SaveColumns::Name);
|
QTableWidgetItem* item = m_list->item(idx, static_cast<int>(SaveColumns::Name));
|
||||||
if (!item)
|
if (!item)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -655,8 +674,8 @@ void save_manager_dialog::UpdateDetails()
|
||||||
WaitForRepaintThreads(false);
|
WaitForRepaintThreads(false);
|
||||||
|
|
||||||
const int row = m_list->currentRow();
|
const int row = m_list->currentRow();
|
||||||
QTableWidgetItem* item = m_list->item(row, SaveColumns::Name);
|
QTableWidgetItem* item = m_list->item(row, static_cast<int>(SaveColumns::Name));
|
||||||
movie_item* icon_item = static_cast<movie_item*>(m_list->item(row, SaveColumns::Icon));
|
movie_item* icon_item = static_cast<movie_item*>(m_list->item(row, static_cast<int>(SaveColumns::Icon)));
|
||||||
|
|
||||||
if (!item || !icon_item)
|
if (!item || !icon_item)
|
||||||
{
|
{
|
||||||
|
|
@ -692,7 +711,7 @@ void save_manager_dialog::WaitForRepaintThreads(bool abort)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_list->rowCount(); i++)
|
for (int i = 0; i < m_list->rowCount(); i++)
|
||||||
{
|
{
|
||||||
if (movie_item* item = static_cast<movie_item*>(m_list->item(i, SaveColumns::Icon)))
|
if (movie_item* item = static_cast<movie_item*>(m_list->item(i, static_cast<int>(SaveColumns::Icon))))
|
||||||
{
|
{
|
||||||
item->wait_for_icon_loading(abort);
|
item->wait_for_icon_loading(abort);
|
||||||
}
|
}
|
||||||
|
|
@ -706,7 +725,7 @@ void save_manager_dialog::text_changed(const QString& text)
|
||||||
if (text.isEmpty())
|
if (text.isEmpty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for (int col = SaveColumns::Name; col < SaveColumns::Count; col++)
|
for (int col = static_cast<int>(SaveColumns::Name); col < static_cast<int>(SaveColumns::Count); col++)
|
||||||
{
|
{
|
||||||
const QTableWidgetItem* item = m_list->item(row, col);
|
const QTableWidgetItem* item = m_list->item(row, col);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ Q_SIGNALS:
|
||||||
void IconReady(int index, const QPixmap& new_icon);
|
void IconReady(int index, const QPixmap& new_icon);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Init();
|
|
||||||
void UpdateList();
|
void UpdateList();
|
||||||
void UpdateIcons();
|
void UpdateIcons();
|
||||||
void ShowContextMenu(const QPoint& pos);
|
void ShowContextMenu(const QPoint& pos);
|
||||||
|
|
@ -49,6 +48,8 @@ private:
|
||||||
|
|
||||||
std::vector<SaveDataEntry> GetSaveEntries(const std::string& base_dir);
|
std::vector<SaveDataEntry> GetSaveEntries(const std::string& base_dir);
|
||||||
|
|
||||||
|
QString get_header_text(int col) const;
|
||||||
|
|
||||||
game_list* m_list = nullptr;
|
game_list* m_list = nullptr;
|
||||||
std::string m_dir;
|
std::string m_dir;
|
||||||
std::vector<SaveDataEntry> m_save_entries;
|
std::vector<SaveDataEntry> m_save_entries;
|
||||||
|
|
|
||||||
|
|
@ -63,15 +63,16 @@ savestate_manager_dialog::savestate_manager_dialog(std::shared_ptr<gui_settings>
|
||||||
m_game_table->setAlternatingRowColors(true);
|
m_game_table->setAlternatingRowColors(true);
|
||||||
m_game_table->installEventFilter(this);
|
m_game_table->installEventFilter(this);
|
||||||
|
|
||||||
auto add_game_column = [this](gui::savestate_game_list_columns col, const QString& header_text, const QString& action_text)
|
const auto add_game_column = [this](gui::savestate_game_list_columns col)
|
||||||
{
|
{
|
||||||
m_game_table->setHorizontalHeaderItem(static_cast<int>(col), new QTableWidgetItem(header_text));
|
const int column = static_cast<int>(col);
|
||||||
m_game_column_acts.append(new QAction(action_text, this));
|
m_game_table->setHorizontalHeaderItem(column, new QTableWidgetItem(get_gamelist_header_text(column)));
|
||||||
|
m_game_column_acts[column] = new QAction(get_gamelist_action_text(column), this);
|
||||||
};
|
};
|
||||||
|
|
||||||
add_game_column(gui::savestate_game_list_columns::icon, tr("Icon"), tr("Show Icons"));
|
add_game_column(gui::savestate_game_list_columns::icon);
|
||||||
add_game_column(gui::savestate_game_list_columns::name, tr("Game"), tr("Show Games"));
|
add_game_column(gui::savestate_game_list_columns::name);
|
||||||
add_game_column(gui::savestate_game_list_columns::savestates, tr("Savestates"), tr("Show Savestates"));
|
add_game_column(gui::savestate_game_list_columns::savestates);
|
||||||
|
|
||||||
// Savestate Table
|
// Savestate Table
|
||||||
m_savestate_table = new game_list();
|
m_savestate_table = new game_list();
|
||||||
|
|
@ -94,16 +95,17 @@ savestate_manager_dialog::savestate_manager_dialog(std::shared_ptr<gui_settings>
|
||||||
m_savestate_table->setAlternatingRowColors(true);
|
m_savestate_table->setAlternatingRowColors(true);
|
||||||
m_savestate_table->installEventFilter(this);
|
m_savestate_table->installEventFilter(this);
|
||||||
|
|
||||||
auto add_savestate_column = [this](gui::savestate_list_columns col, const QString& header_text, const QString& action_text)
|
const auto add_savestate_column = [this](gui::savestate_list_columns col)
|
||||||
{
|
{
|
||||||
m_savestate_table->setHorizontalHeaderItem(static_cast<int>(col), new QTableWidgetItem(header_text));
|
const int column = static_cast<int>(col);
|
||||||
m_savestate_column_acts.append(new QAction(action_text, this));
|
m_savestate_table->setHorizontalHeaderItem(column, new QTableWidgetItem(get_savestate_header_text(column)));
|
||||||
|
m_savestate_column_acts[column] = new QAction(get_savestate_action_text(column), this);
|
||||||
};
|
};
|
||||||
|
|
||||||
add_savestate_column(gui::savestate_list_columns::name, tr("Name"), tr("Show Names"));
|
add_savestate_column(gui::savestate_list_columns::name);
|
||||||
add_savestate_column(gui::savestate_list_columns::compatible, tr("Compatible"), tr("Show Compatible"));
|
add_savestate_column(gui::savestate_list_columns::compatible);
|
||||||
add_savestate_column(gui::savestate_list_columns::date, tr("Created"), tr("Show Created"));
|
add_savestate_column(gui::savestate_list_columns::date);
|
||||||
add_savestate_column(gui::savestate_list_columns::path, tr("Path"), tr("Show Paths"));
|
add_savestate_column(gui::savestate_list_columns::path);
|
||||||
|
|
||||||
m_splitter = new QSplitter();
|
m_splitter = new QSplitter();
|
||||||
m_splitter->addWidget(m_game_table);
|
m_splitter->addWidget(m_game_table);
|
||||||
|
|
@ -220,6 +222,56 @@ savestate_manager_dialog::~savestate_manager_dialog()
|
||||||
WaitAndAbortGameRepaintThreads();
|
WaitAndAbortGameRepaintThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString savestate_manager_dialog::get_savestate_header_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<gui::savestate_list_columns>(col))
|
||||||
|
{
|
||||||
|
case gui::savestate_list_columns::name: return tr("Name");
|
||||||
|
case gui::savestate_list_columns::compatible: return tr("Compatible");
|
||||||
|
case gui::savestate_list_columns::date: return tr("Created");
|
||||||
|
case gui::savestate_list_columns::path: return tr("Path");
|
||||||
|
case gui::savestate_list_columns::count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString savestate_manager_dialog::get_savestate_action_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<gui::savestate_list_columns>(col))
|
||||||
|
{
|
||||||
|
case gui::savestate_list_columns::name: return tr("Show Names");
|
||||||
|
case gui::savestate_list_columns::compatible: return tr("Show Compatible");
|
||||||
|
case gui::savestate_list_columns::date: return tr("Show Created");
|
||||||
|
case gui::savestate_list_columns::path: return tr("Show Paths");
|
||||||
|
case gui::savestate_list_columns::count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString savestate_manager_dialog::get_gamelist_header_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<gui::savestate_game_list_columns>(col))
|
||||||
|
{
|
||||||
|
case gui::savestate_game_list_columns::icon: return tr("Icon");
|
||||||
|
case gui::savestate_game_list_columns::name: return tr("Game");
|
||||||
|
case gui::savestate_game_list_columns::savestates: return tr("Savestates");
|
||||||
|
case gui::savestate_game_list_columns::count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString savestate_manager_dialog::get_gamelist_action_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<gui::savestate_game_list_columns>(col))
|
||||||
|
{
|
||||||
|
case gui::savestate_game_list_columns::icon: return tr("Show Icons");
|
||||||
|
case gui::savestate_game_list_columns::name: return tr("Show Games");
|
||||||
|
case gui::savestate_game_list_columns::savestates: return tr("Show Savestates");
|
||||||
|
case gui::savestate_game_list_columns::count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool savestate_manager_dialog::LoadSavestateFolderToDB(std::unique_ptr<game_savestates_data>&& game_savestates)
|
bool savestate_manager_dialog::LoadSavestateFolderToDB(std::unique_ptr<game_savestates_data>&& game_savestates)
|
||||||
{
|
{
|
||||||
ensure(!!game_savestates);
|
ensure(!!game_savestates);
|
||||||
|
|
@ -625,6 +677,21 @@ void savestate_manager_dialog::PopulateGameTable()
|
||||||
m_game_table->clearContents();
|
m_game_table->clearContents();
|
||||||
m_game_table->setRowCount(static_cast<int>(m_savestate_db.size()));
|
m_game_table->setRowCount(static_cast<int>(m_savestate_db.size()));
|
||||||
|
|
||||||
|
// Update headers
|
||||||
|
for (int col = 0; col < m_game_table->horizontalHeader()->count(); col++)
|
||||||
|
{
|
||||||
|
if (auto item = m_game_table->horizontalHeaderItem(col))
|
||||||
|
{
|
||||||
|
item->setText(get_gamelist_header_text(col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update actions
|
||||||
|
for (auto& [col, action] : m_game_column_acts)
|
||||||
|
{
|
||||||
|
action->setText(get_gamelist_action_text(col));
|
||||||
|
}
|
||||||
|
|
||||||
m_game_combo->clear();
|
m_game_combo->clear();
|
||||||
m_game_combo->blockSignals(true);
|
m_game_combo->blockSignals(true);
|
||||||
|
|
||||||
|
|
@ -681,6 +748,21 @@ void savestate_manager_dialog::PopulateSavestateTable()
|
||||||
m_savestate_table->setRowCount(static_cast<int>(savestates.size()));
|
m_savestate_table->setRowCount(static_cast<int>(savestates.size()));
|
||||||
m_savestate_table->setSortingEnabled(false); // Disable sorting before using setItem calls
|
m_savestate_table->setSortingEnabled(false); // Disable sorting before using setItem calls
|
||||||
|
|
||||||
|
// Update headers
|
||||||
|
for (int col = 0; col < m_savestate_table->horizontalHeader()->count(); col++)
|
||||||
|
{
|
||||||
|
if (auto item = m_savestate_table->horizontalHeaderItem(col))
|
||||||
|
{
|
||||||
|
item->setText(get_savestate_header_text(col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update actions
|
||||||
|
for (auto& [col, action] : m_savestate_column_acts)
|
||||||
|
{
|
||||||
|
action->setText(get_savestate_action_text(col));
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < static_cast<int>(savestates.size()); i++)
|
for (int i = 0; i < static_cast<int>(savestates.size()); i++)
|
||||||
{
|
{
|
||||||
const savestate_data& savestate = savestates[i];
|
const savestate_data& savestate = savestates[i];
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,12 @@ private:
|
||||||
void closeEvent(QCloseEvent *event) override;
|
void closeEvent(QCloseEvent *event) override;
|
||||||
bool eventFilter(QObject *object, QEvent *event) override;
|
bool eventFilter(QObject *object, QEvent *event) override;
|
||||||
|
|
||||||
|
QString get_savestate_header_text(int col) const;
|
||||||
|
QString get_savestate_action_text(int col) const;
|
||||||
|
|
||||||
|
QString get_gamelist_header_text(int col) const;
|
||||||
|
QString get_gamelist_action_text(int col) const;
|
||||||
|
|
||||||
std::shared_ptr<gui_settings> m_gui_settings;
|
std::shared_ptr<gui_settings> m_gui_settings;
|
||||||
|
|
||||||
std::vector<game_info> m_game_info;
|
std::vector<game_info> m_game_info;
|
||||||
|
|
@ -74,8 +80,8 @@ private:
|
||||||
game_list* m_savestate_table; //! UI element to display savestate stuff.
|
game_list* m_savestate_table; //! UI element to display savestate stuff.
|
||||||
game_list* m_game_table; //! UI element to display games.
|
game_list* m_game_table; //! UI element to display games.
|
||||||
|
|
||||||
QList<QAction*> m_savestate_column_acts;
|
std::map<int, QAction*> m_savestate_column_acts;
|
||||||
QList<QAction*> m_game_column_acts;
|
std::map<int, QAction*> m_game_column_acts;
|
||||||
|
|
||||||
int m_game_icon_size_index = 25;
|
int m_game_icon_size_index = 25;
|
||||||
QSize m_game_icon_size = QSize(m_game_icon_size_index, m_game_icon_size_index);
|
QSize m_game_icon_size = QSize(m_game_icon_size_index, m_game_icon_size_index);
|
||||||
|
|
|
||||||
|
|
@ -100,16 +100,17 @@ trophy_manager_dialog::trophy_manager_dialog(std::shared_ptr<gui_settings> gui_s
|
||||||
m_game_table->setAlternatingRowColors(true);
|
m_game_table->setAlternatingRowColors(true);
|
||||||
m_game_table->installEventFilter(this);
|
m_game_table->installEventFilter(this);
|
||||||
|
|
||||||
auto add_game_column = [this](gui::trophy_game_list_columns col, const QString& header_text, const QString& action_text)
|
const auto add_game_column = [this](gui::trophy_game_list_columns col)
|
||||||
{
|
{
|
||||||
m_game_table->setHorizontalHeaderItem(static_cast<int>(col), new QTableWidgetItem(header_text));
|
const int column = static_cast<int>(col);
|
||||||
m_game_column_acts.append(new QAction(action_text, this));
|
m_game_table->setHorizontalHeaderItem(column, new QTableWidgetItem(get_gamelist_header_text(column)));
|
||||||
|
m_game_column_acts[column] = new QAction(get_gamelist_action_text(column), this);
|
||||||
};
|
};
|
||||||
|
|
||||||
add_game_column(gui::trophy_game_list_columns::icon, tr("Icon"), tr("Show Icons"));
|
add_game_column(gui::trophy_game_list_columns::icon);
|
||||||
add_game_column(gui::trophy_game_list_columns::name, tr("Game"), tr("Show Games"));
|
add_game_column(gui::trophy_game_list_columns::name);
|
||||||
add_game_column(gui::trophy_game_list_columns::progress, tr("Progress"), tr("Show Progress"));
|
add_game_column(gui::trophy_game_list_columns::progress);
|
||||||
add_game_column(gui::trophy_game_list_columns::trophies, tr("Trophies"), tr("Show Trophies"));
|
add_game_column(gui::trophy_game_list_columns::trophies);
|
||||||
|
|
||||||
// Trophy Table
|
// Trophy Table
|
||||||
m_trophy_table = new game_list();
|
m_trophy_table = new game_list();
|
||||||
|
|
@ -133,20 +134,21 @@ trophy_manager_dialog::trophy_manager_dialog(std::shared_ptr<gui_settings> gui_s
|
||||||
m_trophy_table->setAlternatingRowColors(true);
|
m_trophy_table->setAlternatingRowColors(true);
|
||||||
m_trophy_table->installEventFilter(this);
|
m_trophy_table->installEventFilter(this);
|
||||||
|
|
||||||
auto add_trophy_column = [this](gui::trophy_list_columns col, const QString& header_text, const QString& action_text)
|
const auto add_trophy_column = [this](gui::trophy_list_columns col)
|
||||||
{
|
{
|
||||||
m_trophy_table->setHorizontalHeaderItem(static_cast<int>(col), new QTableWidgetItem(header_text));
|
const int column = static_cast<int>(col);
|
||||||
m_trophy_column_acts.append(new QAction(action_text, this));
|
m_trophy_table->setHorizontalHeaderItem(column, new QTableWidgetItem(get_trophy_header_text(column)));
|
||||||
|
m_trophy_column_acts[column] = new QAction(get_trophy_action_text(column), this);
|
||||||
};
|
};
|
||||||
|
|
||||||
add_trophy_column(gui::trophy_list_columns::icon, tr("Icon"), tr("Show Icons"));
|
add_trophy_column(gui::trophy_list_columns::icon);
|
||||||
add_trophy_column(gui::trophy_list_columns::name, tr("Name"), tr("Show Names"));
|
add_trophy_column(gui::trophy_list_columns::name);
|
||||||
add_trophy_column(gui::trophy_list_columns::description, tr("Description"), tr("Show Descriptions"));
|
add_trophy_column(gui::trophy_list_columns::description);
|
||||||
add_trophy_column(gui::trophy_list_columns::type, tr("Type"), tr("Show Types"));
|
add_trophy_column(gui::trophy_list_columns::type);
|
||||||
add_trophy_column(gui::trophy_list_columns::is_unlocked, tr("Status"), tr("Show Status"));
|
add_trophy_column(gui::trophy_list_columns::is_unlocked);
|
||||||
add_trophy_column(gui::trophy_list_columns::id, tr("ID"), tr("Show IDs"));
|
add_trophy_column(gui::trophy_list_columns::id);
|
||||||
add_trophy_column(gui::trophy_list_columns::platinum_link, tr("Platinum Relevant"), tr("Show Platinum Relevant"));
|
add_trophy_column(gui::trophy_list_columns::platinum_link);
|
||||||
add_trophy_column(gui::trophy_list_columns::time_unlocked, tr("Time Unlocked"), tr("Show Time Unlocked"));
|
add_trophy_column(gui::trophy_list_columns::time_unlocked);
|
||||||
|
|
||||||
m_splitter = new QSplitter();
|
m_splitter = new QSplitter();
|
||||||
m_splitter->addWidget(m_game_table);
|
m_splitter->addWidget(m_game_table);
|
||||||
|
|
@ -406,6 +408,66 @@ trophy_manager_dialog::~trophy_manager_dialog()
|
||||||
WaitAndAbortTrophyRepaintThreads();
|
WaitAndAbortTrophyRepaintThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString trophy_manager_dialog::get_trophy_header_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<gui::trophy_list_columns>(col))
|
||||||
|
{
|
||||||
|
case gui::trophy_list_columns::icon: return tr("Icon");
|
||||||
|
case gui::trophy_list_columns::name: return tr("Name");
|
||||||
|
case gui::trophy_list_columns::description: return tr("Description");
|
||||||
|
case gui::trophy_list_columns::type: return tr("Type");
|
||||||
|
case gui::trophy_list_columns::is_unlocked: return tr("Status");
|
||||||
|
case gui::trophy_list_columns::id: return tr("ID");
|
||||||
|
case gui::trophy_list_columns::platinum_link: return tr("Platinum Relevant");
|
||||||
|
case gui::trophy_list_columns::time_unlocked: return tr("Time Unlocked");
|
||||||
|
case gui::trophy_list_columns::count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString trophy_manager_dialog::get_trophy_action_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<gui::trophy_list_columns>(col))
|
||||||
|
{
|
||||||
|
case gui::trophy_list_columns::icon: return tr("Show Icons");
|
||||||
|
case gui::trophy_list_columns::name: return tr("Show Names");
|
||||||
|
case gui::trophy_list_columns::description: return tr("Show Descriptions");
|
||||||
|
case gui::trophy_list_columns::type: return tr("Show Types");
|
||||||
|
case gui::trophy_list_columns::is_unlocked: return tr("Show Status");
|
||||||
|
case gui::trophy_list_columns::id: return tr("Show IDs");
|
||||||
|
case gui::trophy_list_columns::platinum_link: return tr("Show Platinum Relevant");
|
||||||
|
case gui::trophy_list_columns::time_unlocked: return tr("Show Time Unlocked");
|
||||||
|
case gui::trophy_list_columns::count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString trophy_manager_dialog::get_gamelist_header_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<gui::trophy_game_list_columns>(col))
|
||||||
|
{
|
||||||
|
case gui::trophy_game_list_columns::icon: return tr("Icon");
|
||||||
|
case gui::trophy_game_list_columns::name: return tr("Game");
|
||||||
|
case gui::trophy_game_list_columns::progress: return tr("Progress");
|
||||||
|
case gui::trophy_game_list_columns::trophies: return tr("Trophies");
|
||||||
|
case gui::trophy_game_list_columns::count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString trophy_manager_dialog::get_gamelist_action_text(int col) const
|
||||||
|
{
|
||||||
|
switch (static_cast<gui::trophy_game_list_columns>(col))
|
||||||
|
{
|
||||||
|
case gui::trophy_game_list_columns::icon: return tr("Show Icons");
|
||||||
|
case gui::trophy_game_list_columns::name: return tr("Show Games");
|
||||||
|
case gui::trophy_game_list_columns::progress: return tr("Show Progress");
|
||||||
|
case gui::trophy_game_list_columns::trophies: return tr("Show Trophies");
|
||||||
|
case gui::trophy_game_list_columns::count: break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool trophy_manager_dialog::LoadTrophyFolderToDB(const std::string& trop_name)
|
bool trophy_manager_dialog::LoadTrophyFolderToDB(const std::string& trop_name)
|
||||||
{
|
{
|
||||||
const std::string trophy_path = m_trophy_dir + trop_name;
|
const std::string trophy_path = m_trophy_dir + trop_name;
|
||||||
|
|
@ -1062,6 +1124,21 @@ void trophy_manager_dialog::PopulateGameTable()
|
||||||
m_game_table->clearContents();
|
m_game_table->clearContents();
|
||||||
m_game_table->setRowCount(static_cast<int>(m_trophies_db.size()));
|
m_game_table->setRowCount(static_cast<int>(m_trophies_db.size()));
|
||||||
|
|
||||||
|
// Update headers
|
||||||
|
for (int col = 0; col < m_game_table->horizontalHeader()->count(); col++)
|
||||||
|
{
|
||||||
|
if (auto item = m_game_table->horizontalHeaderItem(col))
|
||||||
|
{
|
||||||
|
item->setText(get_gamelist_header_text(col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update actions
|
||||||
|
for (auto& [col, action] : m_game_column_acts)
|
||||||
|
{
|
||||||
|
action->setText(get_gamelist_action_text(col));
|
||||||
|
}
|
||||||
|
|
||||||
m_game_combo->clear();
|
m_game_combo->clear();
|
||||||
m_game_combo->blockSignals(true);
|
m_game_combo->blockSignals(true);
|
||||||
|
|
||||||
|
|
@ -1126,6 +1203,21 @@ void trophy_manager_dialog::PopulateTrophyTable()
|
||||||
m_trophy_table->setRowCount(all_trophies);
|
m_trophy_table->setRowCount(all_trophies);
|
||||||
m_trophy_table->setSortingEnabled(false); // Disable sorting before using setItem calls
|
m_trophy_table->setSortingEnabled(false); // Disable sorting before using setItem calls
|
||||||
|
|
||||||
|
// Update headers
|
||||||
|
for (int col = 0; col < m_trophy_table->horizontalHeader()->count(); col++)
|
||||||
|
{
|
||||||
|
if (auto item = m_trophy_table->horizontalHeaderItem(col))
|
||||||
|
{
|
||||||
|
item->setText(get_trophy_header_text(col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update actions
|
||||||
|
for (auto& [col, action] : m_trophy_column_acts)
|
||||||
|
{
|
||||||
|
action->setText(get_trophy_action_text(col));
|
||||||
|
}
|
||||||
|
|
||||||
QPixmap placeholder(m_icon_height, m_icon_height);
|
QPixmap placeholder(m_icon_height, m_icon_height);
|
||||||
placeholder.fill(Qt::transparent);
|
placeholder.fill(Qt::transparent);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,12 @@ private:
|
||||||
static QDateTime TickToDateTime(u64 tick);
|
static QDateTime TickToDateTime(u64 tick);
|
||||||
static u64 DateTimeToTick(QDateTime date_time);
|
static u64 DateTimeToTick(QDateTime date_time);
|
||||||
|
|
||||||
|
QString get_trophy_header_text(int col) const;
|
||||||
|
QString get_trophy_action_text(int col) const;
|
||||||
|
|
||||||
|
QString get_gamelist_header_text(int col) const;
|
||||||
|
QString get_gamelist_action_text(int col) const;
|
||||||
|
|
||||||
std::shared_ptr<gui_settings> m_gui_settings;
|
std::shared_ptr<gui_settings> m_gui_settings;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<GameTrophiesData>> m_trophies_db; //! Holds all the trophy information.
|
std::vector<std::unique_ptr<GameTrophiesData>> m_trophies_db; //! Holds all the trophy information.
|
||||||
|
|
@ -93,8 +99,8 @@ private:
|
||||||
game_list* m_trophy_table; //! UI element to display trophy stuff.
|
game_list* m_trophy_table; //! UI element to display trophy stuff.
|
||||||
game_list* m_game_table; //! UI element to display games.
|
game_list* m_game_table; //! UI element to display games.
|
||||||
|
|
||||||
QList<QAction*> m_trophy_column_acts;
|
std::map<int, QAction*> m_trophy_column_acts;
|
||||||
QList<QAction*> m_game_column_acts;
|
std::map<int, QAction*> m_game_column_acts;
|
||||||
|
|
||||||
bool m_show_hidden_trophies = false;
|
bool m_show_hidden_trophies = false;
|
||||||
bool m_show_unlocked_trophies = true;
|
bool m_show_unlocked_trophies = true;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue