From 39f7549e7a24b4a0369220a5e44fecc81f82617c Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 18 Nov 2024 22:27:17 -0800 Subject: [PATCH 1/2] Save/Restore file dialogs favorites. --- src/core/psxemulator.h | 3 +- src/gui/gui.cc | 16 +++++++++++ src/gui/gui.h | 25 +++++++--------- src/gui/widgets/assembly.h | 6 ++-- src/gui/widgets/filedialog.cc | 13 +++++++++ src/gui/widgets/filedialog.h | 11 ++++++- src/gui/widgets/isobrowser.h | 7 +++-- src/gui/widgets/memcard_manager.h | 9 ++++-- src/gui/widgets/pio-cart.h | 8 ++++-- src/gui/widgets/typed_debugger.cc | 6 +++- src/gui/widgets/typed_debugger.h | 6 ++-- src/main/main.cc | 3 +- src/support/settings.h | 48 +++++++++++++++++++++++++------ 13 files changed, 122 insertions(+), 39 deletions(-) diff --git a/src/core/psxemulator.h b/src/core/psxemulator.h index 1056b281e..8a4d0eb17 100644 --- a/src/core/psxemulator.h +++ b/src/core/psxemulator.h @@ -190,6 +190,7 @@ class Emulator { typedef SettingPath SettingEXP1BrowsePath; typedef Setting SettingPIOConnected; typedef SettingPath SettingMapBrowsePath; + typedef SettingVector SettingOpenDialogFavorites; Settings + SettingPIOConnected, SettingMapBrowsePath, SettingOpenDialogFavorites> settings; class PcsxConfig { public: diff --git a/src/gui/gui.cc b/src/gui/gui.cc index 571ad71bc..472e309e9 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -96,6 +96,22 @@ __declspec(dllexport) DWORD NvOptimusEnablement = 1; __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; } +PCSX::GUI::GUI(std::vector& favorites) + : m_listener(g_system->m_eventBus), + m_typedDebugger(settings.get().value, favorites), + m_memcardManager(settings.get().value, favorites), + m_assembly(settings.get().value, favorites), + m_openIsoFileDialog(l_("Open Disk Image"), favorites), + m_openBinaryDialog(l_("Open Binary"), favorites), + m_openArchiveDialog(l_("Open Archive"), favorites), + m_selectBiosDialog(l_("Select BIOS"), favorites), + m_selectEXP1Dialog(l_("Select EXP1"), favorites), + m_isoBrowser(settings.get().value, favorites), + m_pioCart(settings.get().value, favorites) { + assert(g_gui == nullptr); + g_gui = this; +} + void PCSX::GUI::openUrl(std::string_view url) { std::string storage = std::string(url); ShellExecuteA(0, 0, storage.c_str(), 0, 0, SW_SHOW); diff --git a/src/gui/gui.h b/src/gui/gui.h index 4c91c749d..41c0d99b0 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -213,10 +213,7 @@ class GUI final : public UI { GUI *m_gui = nullptr; }; std::vector getGLerrors() { return std::move(m_glErrors); } - GUI() : m_listener(g_system->m_eventBus) { - assert(g_gui == nullptr); - g_gui = this; - } + GUI(std::vector &favorites); ~GUI() { assert(g_gui == this); g_gui = nullptr; @@ -374,20 +371,20 @@ class GUI final : public UI { MemoryEditorWrapper m_vramEditor = {this, settings.get().value, settings.get().value}; Widgets::MemoryObserver m_memoryObserver = {settings.get().value}; - Widgets::TypedDebugger m_typedDebugger = {settings.get().value}; + Widgets::TypedDebugger m_typedDebugger; Widgets::Patches m_patches = {settings.get().value}; - Widgets::MemcardManager m_memcardManager = {settings.get().value}; + Widgets::MemcardManager m_memcardManager; Widgets::Registers m_registers = {settings.get().value}; - Widgets::Assembly m_assembly = {settings.get().value}; + Widgets::Assembly m_assembly; Widgets::Disassembly m_disassembly = {settings.get().value}; - Widgets::FileDialog<> m_openIsoFileDialog = {l_("Open Disk Image")}; - Widgets::FileDialog<> m_openBinaryDialog = {l_("Open Binary")}; - Widgets::FileDialog<> m_openArchiveDialog = {l_("Open Archive")}; - Widgets::FileDialog<> m_selectBiosDialog = {l_("Select BIOS")}; - Widgets::FileDialog<> m_selectEXP1Dialog = {l_("Select EXP1")}; + Widgets::FileDialog<> m_openIsoFileDialog; + Widgets::FileDialog<> m_openBinaryDialog; + Widgets::FileDialog<> m_openArchiveDialog; + Widgets::FileDialog<> m_selectBiosDialog; + Widgets::FileDialog<> m_selectEXP1Dialog; Widgets::NamedSaveStates m_namedSaveStates = {settings.get().value}; Widgets::Breakpoints m_breakpoints = {settings.get().value}; - Widgets::IsoBrowser m_isoBrowser = {settings.get().value}; + Widgets::IsoBrowser m_isoBrowser; bool m_showCfg = false; bool m_showUiCfg = false; @@ -408,7 +405,7 @@ class GUI final : public UI { Widgets::CallStacks m_callstacks = {settings.get().value}; - Widgets::PIOCart m_pioCart = {settings.get().value}; + Widgets::PIOCart m_pioCart; Widgets::SIO1 m_sio1 = {settings.get().value}; Widgets::GPULogger m_gpuLogger{settings.get().value}; diff --git a/src/gui/widgets/assembly.h b/src/gui/widgets/assembly.h index 2fbff4f4f..edd2bd849 100644 --- a/src/gui/widgets/assembly.h +++ b/src/gui/widgets/assembly.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "core/disr3000a.h" #include "core/r3000a.h" @@ -42,7 +43,8 @@ namespace Widgets { class Assembly : private Disasm { public: - Assembly(bool& show) : m_show(show), m_listener(g_system->m_eventBus) { + Assembly(bool& show, std::vector& favorites) + : m_show(show), m_listener(g_system->m_eventBus), m_symbolsFileDialog(l_("Load Symbols"), favorites) { m_listener.listen([this](const auto& event) { m_jumpToPC = event.pc; }); memset(m_jumpAddressString, 0, sizeof(m_jumpAddressString)); } @@ -60,7 +62,7 @@ class Assembly : private Disasm { int m_numColumns = 4; char m_jumpAddressString[20]; uint32_t m_previousPC = 0; - FileDialog<> m_symbolsFileDialog = {l_("Load Symbols")}; + FileDialog<> m_symbolsFileDialog; std::vector> m_arrows; // Disasm section diff --git a/src/gui/widgets/filedialog.cc b/src/gui/widgets/filedialog.cc index d35d76933..fe826336d 100644 --- a/src/gui/widgets/filedialog.cc +++ b/src/gui/widgets/filedialog.cc @@ -43,3 +43,16 @@ void PCSX::Widgets::FileDialogBase::setDeleteTexture() { glDeleteTextures(1, &texID); }; } + +void PCSX::Widgets::FileDialogBase::restoreFavorites() { + for (const auto& fav : m_favorites) { + AddFavorite(fav); + } +} + +void PCSX::Widgets::FileDialogBase::saveFavorites() { + m_favorites.clear(); + for (const auto& fav : GetFavorites()) { + m_favorites.push_back(fav); + } +} diff --git a/src/gui/widgets/filedialog.h b/src/gui/widgets/filedialog.h index 8e86431fe..6558160ee 100644 --- a/src/gui/widgets/filedialog.h +++ b/src/gui/widgets/filedialog.h @@ -33,9 +33,15 @@ namespace Widgets { class FileDialogBase : protected ifd::FileDialog { public: virtual void* CreateTexture(uint8_t* data, int w, int h, char fmt) override; + FileDialogBase(std::vector& favorites) : ifd::FileDialog(), m_favorites(favorites) {} protected: void setDeleteTexture(); + void restoreFavorites(); + void saveFavorites(); + + private: + std::vector& m_favorites; }; enum class FileDialogMode { Open, MultiSelect, Save }; @@ -43,13 +49,15 @@ enum class FileDialogMode { Open, MultiSelect, Save }; template class FileDialog : public FileDialogBase { public: - FileDialog(std::function title) : m_title(title) { + FileDialog(std::function title, std::vector& favorites) + : FileDialogBase(favorites), m_title(title) { setToCurrentPath(); setDeleteTexture(); } virtual ~FileDialog() = default; void setToCurrentPath() { m_currentPath = std::filesystem::current_path(); } void openDialog() { + restoreFavorites(); if constexpr (mode == FileDialogMode::Open) { Open(m_title(), m_title(), "*.*", mode == FileDialogMode::MultiSelect, reinterpret_cast(m_currentPath.u8string().c_str())); @@ -67,6 +75,7 @@ class FileDialog : public FileDialogBase { m_results.reserve(results.size()); for (auto& result : results) m_results.push_back(result.u8string()); Close(); + saveFavorites(); } return done; } diff --git a/src/gui/widgets/isobrowser.h b/src/gui/widgets/isobrowser.h index 42dc99110..cff66374c 100644 --- a/src/gui/widgets/isobrowser.h +++ b/src/gui/widgets/isobrowser.h @@ -22,6 +22,8 @@ #include #include +#include +#include #include "gui/widgets/filedialog.h" #include "support/coroutine.h" @@ -35,7 +37,8 @@ namespace Widgets { class IsoBrowser { public: - IsoBrowser(bool& show) : m_show(show) {} + IsoBrowser(bool& show, std::vector& favorites) + : m_show(show), m_openIsoFileDialog(l_("Open Disk Image"), favorites) {} void draw(CDRom* cdrom, const char* title); bool& m_show; @@ -47,7 +50,7 @@ class IsoBrowser { float m_crcProgress = 0.0f; Coroutine<> computeCRC(CDRIso*); - FileDialog<> m_openIsoFileDialog = {l_("Open Disk Image")}; + FileDialog<> m_openIsoFileDialog; }; } // namespace Widgets diff --git a/src/gui/widgets/memcard_manager.h b/src/gui/widgets/memcard_manager.h index dff8f4f60..db74f0740 100644 --- a/src/gui/widgets/memcard_manager.h +++ b/src/gui/widgets/memcard_manager.h @@ -38,7 +38,10 @@ namespace Widgets { class MemcardManager { public: - MemcardManager(bool& show) : m_show(show) {} + MemcardManager(bool& show, std::vector& favorites) + : m_show(show), + m_importMemoryCardDialog(l_("Import Memory Card file"), favorites), + m_exportMemoryCardDialog(l_("Export Memory Card file"), favorites) {} bool draw(GUI* gui, const char* title); bool& m_show; // The framecount from 0 to 59 inclusive. We need it to know which frame of multi-animation @@ -73,8 +76,8 @@ class MemcardManager { int m_undoIndex = 0; std::unique_ptr m_latest; - Widgets::FileDialog<> m_importMemoryCardDialog = {l_("Import Memory Card file")}; - Widgets::FileDialog m_exportMemoryCardDialog = {l_("Export Memory Card file")}; + Widgets::FileDialog<> m_importMemoryCardDialog; + Widgets::FileDialog m_exportMemoryCardDialog; unsigned m_memoryCardImportExportIndex = 0; void clearUndoBuffer() { diff --git a/src/gui/widgets/pio-cart.h b/src/gui/widgets/pio-cart.h index 1e7a15055..85ec84e5e 100644 --- a/src/gui/widgets/pio-cart.h +++ b/src/gui/widgets/pio-cart.h @@ -19,7 +19,8 @@ #pragma once -#include +#include +#include #include "gui/widgets/filedialog.h" @@ -28,12 +29,13 @@ namespace PCSX { namespace Widgets { class PIOCart { public: - PIOCart(bool& show) : m_show(show) {} + PIOCart(bool& show, std::vector& favorites) + : m_show(show), m_selectEXP1Dialog(l_("Select EXP1"), favorites) {} bool draw(const char* title); bool& m_show; private: - Widgets::FileDialog<> m_selectEXP1Dialog = {l_("Select EXP1")}; + Widgets::FileDialog<> m_selectEXP1Dialog; int m_flashSizeIndex; bool m_switchOn = 1; }; diff --git a/src/gui/widgets/typed_debugger.cc b/src/gui/widgets/typed_debugger.cc index 1281d5afc..55e68357e 100644 --- a/src/gui/widgets/typed_debugger.cc +++ b/src/gui/widgets/typed_debugger.cc @@ -138,7 +138,11 @@ void PCSX::Widgets::TypedDebugger::import(std::string_view fileContents, ImportT } } -PCSX::Widgets::TypedDebugger::TypedDebugger(bool& show) : m_show(show), m_listener(g_system->m_eventBus) { +PCSX::Widgets::TypedDebugger::TypedDebugger(bool& show, std::vector& favorites) + : m_show(show), + m_listener(g_system->m_eventBus), + m_importDataTypesFileDialog(l_("Import data types"), favorites), + m_importFunctionsFileDialog(l_("Import functions"), favorites) { m_listener.listen([this](const auto& event) { m_displayedWatchData.clear(); for (const auto* bp : m_watchBreakpoints) { diff --git a/src/gui/widgets/typed_debugger.h b/src/gui/widgets/typed_debugger.h index 4b20e302e..7de667393 100644 --- a/src/gui/widgets/typed_debugger.h +++ b/src/gui/widgets/typed_debugger.h @@ -38,16 +38,16 @@ class TypedDebugger { public: void draw(const char* title, GUI* gui); bool& m_show; - TypedDebugger(bool& show); + TypedDebugger(bool& show, std::vector& favorites); private: /** * Data importation. */ std::vector m_dataTypesFile; - Widgets::FileDialog<> m_importDataTypesFileDialog = {l_("Import data types")}; + Widgets::FileDialog<> m_importDataTypesFileDialog; std::vector m_functionsFile; - Widgets::FileDialog<> m_importFunctionsFileDialog = {l_("Import functions")}; + Widgets::FileDialog<> m_importFunctionsFileDialog; enum class ImportType { DataTypes, Functions }; void import(std::string_view filename, ImportType importType); diff --git a/src/main/main.cc b/src/main/main.cc index 110ab8bf4..36591940d 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -220,9 +220,10 @@ int pcsxMain(int argc, char **argv) { // At this point, we're committed to run the emulator, so we first create it, and the UI next. PCSX::Emulator *emulator = new PCSX::Emulator(); PCSX::g_emulator = emulator; + auto &favorites = emulator->settings.get().value; s_ui = args.get("no-ui") || args.get("cli") ? reinterpret_cast(new PCSX::TUI()) - : reinterpret_cast(new PCSX::GUI()); + : reinterpret_cast(new PCSX::GUI(favorites)); // Settings will be loaded after this initialization. s_ui->init([&emulator, &args, &system]() { // Start tweaking / sanitizing settings a bit, while continuing to parse the command line diff --git a/src/support/settings.h b/src/support/settings.h index 4f65c5e58..9e3e964b2 100644 --- a/src/support/settings.h +++ b/src/support/settings.h @@ -37,6 +37,7 @@ SOFTWARE. #include #include #include +#include #include "core/system.h" #include "json.hpp" @@ -47,6 +48,36 @@ SOFTWARE. namespace PCSX { +namespace concepts { +template +concept Setting = requires(S s) { + { s.serialize() } -> std::same_as; + { s.deserialize(std::declval()) } -> std::same_as; + { s.reset() } -> std::same_as; + { s.pushLuaClosures(std::declval()) } -> std::same_as; +}; +template +concept Settings = requires(S s) { + { s.reset() } -> std::same_as; + { s.serialize() } -> std::same_as; + { s.deserialize(std::declval()) } -> std::same_as; + { s.pushValue(std::declval()) } -> std::same_as; +}; +} // namespace concepts + +template +struct SettingVector; +template +struct SettingVector> { + using json = nlohmann::json; + typedef irqus::typestring name; + json serialize() const { return value; } + void deserialize(const json &j) { value = j.template get>(); } + void reset() { value.clear(); } + std::vector value; + void pushLuaClosures(Lua L) {} +}; + template struct Setting; template @@ -275,9 +306,9 @@ struct SettingFloat, defaultValue, divisor> { float value = (float)defaultValue / (float)divisor; }; -template +template struct SettingNested; -template +template struct SettingNested, nestedSettings> : public nestedSettings { typedef irqus::typestring name; @@ -306,7 +337,7 @@ struct SettingNested, nestedSettings> : public nestedSet } }; -template +template struct Settings : private std::tuple { using json = nlohmann::json; template @@ -336,6 +367,8 @@ struct Settings : private std::tuple { L.declareFunc("__pairs", lua_pairswrapper, -1); L.setmetatable(); } + + private: static int lua_index(lua_State *L_) { Lua L(L_); int r = L.getmetatable(-2); @@ -384,10 +417,9 @@ struct Settings : private std::tuple { return 3; } - private: template constexpr void reset() {} - template + template constexpr void reset() { settingType &setting = std::get(*this); setting.reset(); @@ -395,7 +427,7 @@ struct Settings : private std::tuple { } template constexpr void serialize(json &j) const {} - template + template constexpr void serialize(json &j) const { const settingType &setting = std::get(*this); j[settingType::name::data()] = setting.serialize(); @@ -403,7 +435,7 @@ struct Settings : private std::tuple { } template constexpr void deserialize(const json &j, bool doReset = true) {} - template + template constexpr void deserialize(const json &j, bool doReset = true) { settingType &setting = std::get(*this); try { @@ -419,7 +451,7 @@ struct Settings : private std::tuple { } template void pushValue(Lua L) {} - template + template void pushValue(Lua L) { settingType &setting = std::get(*this); setting.pushLuaClosures(L); From f06ba3caf9455adfa71fa51b91a639d426534b07 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 18 Nov 2024 23:00:05 -0800 Subject: [PATCH 2/2] Fixing Linux build. --- src/gui/gui.cc | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/gui/gui.cc b/src/gui/gui.cc index 472e309e9..3f313671f 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -96,22 +96,6 @@ __declspec(dllexport) DWORD NvOptimusEnablement = 1; __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; } -PCSX::GUI::GUI(std::vector& favorites) - : m_listener(g_system->m_eventBus), - m_typedDebugger(settings.get().value, favorites), - m_memcardManager(settings.get().value, favorites), - m_assembly(settings.get().value, favorites), - m_openIsoFileDialog(l_("Open Disk Image"), favorites), - m_openBinaryDialog(l_("Open Binary"), favorites), - m_openArchiveDialog(l_("Open Archive"), favorites), - m_selectBiosDialog(l_("Select BIOS"), favorites), - m_selectEXP1Dialog(l_("Select EXP1"), favorites), - m_isoBrowser(settings.get().value, favorites), - m_pioCart(settings.get().value, favorites) { - assert(g_gui == nullptr); - g_gui = this; -} - void PCSX::GUI::openUrl(std::string_view url) { std::string storage = std::string(url); ShellExecuteA(0, 0, storage.c_str(), 0, 0, SW_SHOW); @@ -130,6 +114,22 @@ void PCSX::GUI::openUrl(std::string_view url) { } #endif +PCSX::GUI::GUI(std::vector& favorites) + : m_listener(g_system->m_eventBus), + m_typedDebugger(settings.get().value, favorites), + m_memcardManager(settings.get().value, favorites), + m_assembly(settings.get().value, favorites), + m_openIsoFileDialog(l_("Open Disk Image"), favorites), + m_openBinaryDialog(l_("Open Binary"), favorites), + m_openArchiveDialog(l_("Open Archive"), favorites), + m_selectBiosDialog(l_("Select BIOS"), favorites), + m_selectEXP1Dialog(l_("Select EXP1"), favorites), + m_isoBrowser(settings.get().value, favorites), + m_pioCart(settings.get().value, favorites) { + assert(g_gui == nullptr); + g_gui = this; +} + using json = nlohmann::json; static std::function s_imguiUserErrorFunctor = nullptr;