Merge branch 'wheremyfoodat:master' into uwp_clean
This commit is contained in:
4
.github/workflows/Test_Build.yml
vendored
4
.github/workflows/Test_Build.yml
vendored
@@ -35,7 +35,9 @@ jobs:
|
|||||||
- name: Clone and compile 3ds-examples
|
- name: Clone and compile 3ds-examples
|
||||||
run: |
|
run: |
|
||||||
git clone --recursive https://github.com/devkitPro/3ds-examples tests/3ds-examples
|
git clone --recursive https://github.com/devkitPro/3ds-examples tests/3ds-examples
|
||||||
make -C tests/3ds-examples
|
# The devkitpro docker image is outdated and cannot build 3ds-examples at the moment
|
||||||
|
# TODO: Reenable this when it's updated again
|
||||||
|
# make -C tests/3ds-examples
|
||||||
|
|
||||||
- name: Upload binaries
|
- name: Upload binaries
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +206,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;
|
||||||
@@ -286,3 +309,17 @@ const char* EmulatorConfig::languageCodeToString(LanguageCodes code) {
|
|||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user