Qt: Add recent games list

This commit is contained in:
wheremyfoodat
2026-02-24 19:56:51 +02:00
parent f5e5be4b6d
commit 0c1ccbd177
4 changed files with 96 additions and 5 deletions

View File

@@ -108,6 +108,9 @@ struct EmulatorConfig {
std::filesystem::path defaultRomPath = ""; std::filesystem::path defaultRomPath = "";
std::filesystem::path filePath; std::filesystem::path filePath;
static constexpr size_t maxRecentGames = 8;
std::vector<std::filesystem::path> recentlyPlayed;
// Frontend window settings // Frontend window settings
struct WindowSettings { struct WindowSettings {
static constexpr int defaultX = 200; static constexpr int defaultX = 200;
@@ -132,6 +135,8 @@ struct EmulatorConfig {
void load(); void load();
void save(); void save();
void addToRecentGames(const std::filesystem::path& path);
static LanguageCodes languageCodeFromString(std::string inString); static LanguageCodes languageCodeFromString(std::string inString);
static const char* languageCodeToString(LanguageCodes code); static const char* languageCodeToString(LanguageCodes code);
}; };

View File

@@ -103,6 +103,7 @@ class MainWindow : public QMainWindow {
std::vector<EmulatorMessage> messageQueue; std::vector<EmulatorMessage> messageQueue;
QMenuBar* menuBar = nullptr; QMenuBar* menuBar = nullptr;
QMenu* recentsMenu = nullptr;
InputMappings keyboardMappings; InputMappings keyboardMappings;
ScreenWidget* screen; ScreenWidget* screen;
AboutWindow* aboutWindow; AboutWindow* aboutWindow;
@@ -123,6 +124,8 @@ class MainWindow : public QMainWindow {
void emuThreadMainLoop(); void emuThreadMainLoop();
void selectLuaFile(); void selectLuaFile();
void selectROM(); void selectROM();
void loadROMFromPath(const std::filesystem::path& path);
void updateRecentsMenu();
void dumpDspFirmware(); void dumpDspFirmware();
void dumpRomFS(); void dumpRomFS();
void showAboutMenu(); void showAboutMenu();

View File

@@ -50,6 +50,23 @@ void EmulatorConfig::load() {
circlePadProEnabled = toml::find_or<toml::boolean>(general, "EnableCirclePadPro", true); circlePadProEnabled = toml::find_or<toml::boolean>(general, "EnableCirclePadPro", true);
fastmemEnabled = toml::find_or<toml::boolean>(general, "EnableFastmem", enableFastmemDefault); fastmemEnabled = toml::find_or<toml::boolean>(general, "EnableFastmem", enableFastmemDefault);
systemLanguage = languageCodeFromString(toml::find_or<std::string>(general, "SystemLanguage", "en")); systemLanguage = languageCodeFromString(toml::find_or<std::string>(general, "SystemLanguage", "en"));
// Load recent games list
if (general.contains("RecentGames") && general.at("RecentGames").is_array()) {
const auto& recentsArray = general.at("RecentGames").as_array();
recentlyPlayed.clear();
for (const auto& item : recentsArray) {
if (item.is_string()) {
std::filesystem::path gamePath = toml::get<std::string>(item);
recentlyPlayed.push_back(gamePath);
if (recentlyPlayed.size() >= maxRecentGames) {
break;
}
}
}
}
} }
} }
@@ -183,6 +200,12 @@ void EmulatorConfig::save() {
data["General"]["EnableCirclePadPro"] = circlePadProEnabled; data["General"]["EnableCirclePadPro"] = circlePadProEnabled;
data["General"]["EnableFastmem"] = fastmemEnabled; data["General"]["EnableFastmem"] = fastmemEnabled;
toml::array recentsArray;
for (const auto& gamePath : recentlyPlayed) {
recentsArray.push_back(gamePath.string());
}
data["General"]["RecentGames"] = recentsArray;
data["Window"]["AppVersionOnWindow"] = windowSettings.showAppVersion; data["Window"]["AppVersionOnWindow"] = windowSettings.showAppVersion;
data["Window"]["RememberWindowPosition"] = windowSettings.rememberPosition; data["Window"]["RememberWindowPosition"] = windowSettings.rememberPosition;
data["Window"]["WindowPosX"] = windowSettings.x; data["Window"]["WindowPosX"] = windowSettings.x;
@@ -277,4 +300,18 @@ const char* EmulatorConfig::languageCodeToString(LanguageCodes code) {
} else { } else {
return codes[static_cast<u32>(code)]; return codes[static_cast<u32>(code)];
} }
} }
void EmulatorConfig::addToRecentGames(const std::filesystem::path& path) {
// Remove path if it's already in the list
auto it = std::find(recentlyPlayed.begin(), recentlyPlayed.end(), path);
if (it != recentlyPlayed.end()) {
recentlyPlayed.erase(it);
}
recentlyPlayed.insert(recentlyPlayed.begin(), path);
// Limit how many games can be saved
if (recentlyPlayed.size() > maxRecentGames) {
recentlyPlayed.resize(maxRecentGames);
}
}

View File

@@ -53,6 +53,11 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
// Create and bind actions for them // Create and bind actions for them
auto loadGameAction = fileMenu->addAction(tr("Load game")); auto loadGameAction = fileMenu->addAction(tr("Load game"));
recentsMenu = fileMenu->addMenu(tr("Recents"));
updateRecentsMenu();
fileMenu->addSeparator();
auto loadLuaAction = fileMenu->addAction(tr("Load Lua script")); auto loadLuaAction = fileMenu->addAction(tr("Load Lua script"));
auto openAppFolderAction = fileMenu->addAction(tr("Open Panda3DS folder")); auto openAppFolderAction = fileMenu->addAction(tr("Open Panda3DS folder"));
@@ -140,6 +145,10 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
if (!emu->loadROM(romPath)) { if (!emu->loadROM(romPath)) {
// For some reason just .c_str() doesn't show the proper path // For some reason just .c_str() doesn't show the proper path
Helpers::warn("Failed to load ROM file: %s", romPath.string().c_str()); Helpers::warn("Failed to load ROM file: %s", romPath.string().c_str());
} else {
emu->getConfig().addToRecentGames(romPath);
emu->getConfig().save();
updateRecentsMenu();
} }
} }
@@ -240,11 +249,48 @@ void MainWindow::selectROM() {
); );
if (!path.isEmpty()) { if (!path.isEmpty()) {
std::filesystem::path* p = new std::filesystem::path(path.toStdU16String()); loadROMFromPath(std::filesystem::path(path.toStdU16String()));
}
}
EmulatorMessage message{.type = MessageType::LoadROM}; void MainWindow::loadROMFromPath(const std::filesystem::path& path) {
message.path.p = p; std::filesystem::path* p = new std::filesystem::path(path);
sendMessage(message);
EmulatorMessage message{.type = MessageType::LoadROM};
message.path.p = p;
sendMessage(message);
emu->getConfig().addToRecentGames(path);
emu->getConfig().save();
updateRecentsMenu();
}
void MainWindow::updateRecentsMenu() {
recentsMenu->clear();
const auto& recentGames = emu->getConfig().recentlyPlayed;
if (recentGames.empty()) {
// Add a disabled "No recent games" item
QAction* noRecentsAction = recentsMenu->addAction(tr("No recent games"));
noRecentsAction->setEnabled(false);
} else {
for (const auto& gamePath : recentGames) {
QString displayName = QString::fromStdU16String(gamePath.filename().u16string());
QAction* action = recentsMenu->addAction(displayName);
// Store the full path in the action's data, set tooltip to show full path
action->setData(QString::fromStdU16String(gamePath.u16string()));
action->setToolTip(QString::fromStdU16String(gamePath.u16string()));
connect(action, &QAction::triggered, this, [this, gamePath]() { loadROMFromPath(gamePath); });
}
recentsMenu->addSeparator();
QAction* clearAction = recentsMenu->addAction(tr("Clear recent games"));
connect(clearAction, &QAction::triggered, this, [this]() {
emu->getConfig().recentlyPlayed.clear();
emu->getConfig().save();
updateRecentsMenu();
});
} }
} }