mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-12-30 10:37:07 +00:00
UI+build: Isolate wxWidgets code from non-GUI code (#1633)
This commit is contained in:
parent
5f3c2816ec
commit
67de63bed6
199 changed files with 2414 additions and 2091 deletions
|
|
@ -60,14 +60,6 @@ bool ActiveSettings::DisplayDRCEnabled()
|
|||
return g_current_game_profile->StartWithGamepadView();
|
||||
}
|
||||
|
||||
bool ActiveSettings::FullscreenEnabled()
|
||||
{
|
||||
if (LaunchSettings::FullscreenEnabled().has_value())
|
||||
return LaunchSettings::FullscreenEnabled().value();
|
||||
|
||||
return GetConfig().fullscreen;
|
||||
}
|
||||
|
||||
CPUMode ActiveSettings::GetCPUMode()
|
||||
{
|
||||
auto mode = g_current_game_profile->GetCPUMode().value_or(CPUMode::Auto);
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ public:
|
|||
// general
|
||||
[[nodiscard]] static bool LoadSharedLibrariesEnabled();
|
||||
[[nodiscard]] static bool DisplayDRCEnabled();
|
||||
[[nodiscard]] static bool FullscreenEnabled();
|
||||
|
||||
// cpu
|
||||
[[nodiscard]] static CPUMode GetCPUMode();
|
||||
|
|
|
|||
|
|
@ -18,14 +18,9 @@ target_include_directories(CemuConfig PUBLIC "../")
|
|||
target_link_libraries(CemuConfig PRIVATE
|
||||
CemuCafe
|
||||
CemuCommon
|
||||
CemuGui
|
||||
CemuUtil
|
||||
Boost::headers
|
||||
Boost::program_options
|
||||
pugixml::pugixml
|
||||
)
|
||||
|
||||
if (ENABLE_WXWIDGETS)
|
||||
# PUBLIC because wx/language.h is included in CemuConfig.h
|
||||
# Could be made PRIVATE by using 0 instead of wxLANGUAGE_DEFAULT
|
||||
target_link_libraries(CemuConfig PUBLIC wx::base wx::core)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1,23 +1,20 @@
|
|||
#include "config/CemuConfig.h"
|
||||
#include "WindowSystem.h"
|
||||
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
#include <wx/language.h>
|
||||
|
||||
#include "ActiveSettings.h"
|
||||
|
||||
XMLCemuConfig_t g_config(L"settings.xml");
|
||||
|
||||
void CemuConfig::SetMLCPath(fs::path path, bool save)
|
||||
{
|
||||
mlc_path.SetValue(_pathToUtf8(path));
|
||||
if(save)
|
||||
g_config.Save();
|
||||
GetConfigHandle().Save();
|
||||
Account::RefreshAccounts();
|
||||
}
|
||||
|
||||
void CemuConfig::Load(XMLConfigParser& parser)
|
||||
XMLConfigParser CemuConfig::Load(XMLConfigParser& parser)
|
||||
{
|
||||
auto new_parser = parser.get("content");
|
||||
if (new_parser.valid())
|
||||
|
|
@ -33,94 +30,11 @@ void CemuConfig::Load(XMLConfigParser& parser)
|
|||
|
||||
permanent_storage = parser.get("permanent_storage", permanent_storage);
|
||||
|
||||
language = parser.get<sint32>("language", wxLANGUAGE_DEFAULT);
|
||||
use_discord_presence = parser.get("use_discord_presence", true);
|
||||
fullscreen_menubar = parser.get("fullscreen_menubar", false);
|
||||
feral_gamemode = parser.get("feral_gamemode", false);
|
||||
check_update = parser.get("check_update", check_update);
|
||||
receive_untested_updates = parser.get("receive_untested_updates", receive_untested_updates);
|
||||
save_screenshot = parser.get("save_screenshot", save_screenshot);
|
||||
did_show_vulkan_warning = parser.get("vk_warning", did_show_vulkan_warning);
|
||||
did_show_graphic_pack_download = parser.get("gp_download", did_show_graphic_pack_download);
|
||||
did_show_macos_disclaimer = parser.get("macos_disclaimer", did_show_macos_disclaimer);
|
||||
fullscreen = parser.get("fullscreen", fullscreen);
|
||||
proxy_server = parser.get("proxy_server", "");
|
||||
disable_screensaver = parser.get("disable_screensaver", disable_screensaver);
|
||||
play_boot_sound = parser.get("play_boot_sound", play_boot_sound);
|
||||
console_language = parser.get("console_language", console_language.GetInitValue());
|
||||
|
||||
window_position.x = parser.get("window_position").get("x", -1);
|
||||
window_position.y = parser.get("window_position").get("y", -1);
|
||||
|
||||
window_size.x = parser.get("window_size").get("x", -1);
|
||||
window_size.y = parser.get("window_size").get("y", -1);
|
||||
window_maximized = parser.get("window_maximized", false);
|
||||
|
||||
pad_open = parser.get("open_pad", false);
|
||||
pad_position.x = parser.get("pad_position").get("x", -1);
|
||||
pad_position.y = parser.get("pad_position").get("y", -1);
|
||||
|
||||
pad_size.x = parser.get("pad_size").get("x", -1);
|
||||
pad_size.y = parser.get("pad_size").get("y", -1);
|
||||
pad_maximized = parser.get("pad_maximized", false);
|
||||
|
||||
auto gamelist = parser.get("GameList");
|
||||
game_list_style = gamelist.get("style", 0);
|
||||
game_list_column_order = gamelist.get("order", "");
|
||||
|
||||
show_icon_column = parser.get("show_icon_column", true);
|
||||
|
||||
// return default width if value in config file out of range
|
||||
auto loadColumnSize = [&gamelist] (const char *name, uint32 defaultWidth)
|
||||
{
|
||||
sint64 val = gamelist.get(name, DefaultColumnSize::name);
|
||||
if (val < 0 || val > (sint64) std::numeric_limits<uint32>::max)
|
||||
return defaultWidth;
|
||||
return static_cast<uint32>(val);
|
||||
};
|
||||
column_width.name = loadColumnSize("name_width", DefaultColumnSize::name);
|
||||
column_width.version = loadColumnSize("version_width", DefaultColumnSize::version);
|
||||
column_width.dlc = loadColumnSize("dlc_width", DefaultColumnSize::dlc);
|
||||
column_width.game_time = loadColumnSize("game_time_width", DefaultColumnSize::game_time);
|
||||
column_width.game_started = loadColumnSize("game_started_width", DefaultColumnSize::game_started);
|
||||
column_width.region = loadColumnSize("region_width", DefaultColumnSize::region);
|
||||
column_width.title_id = loadColumnSize("title_id", DefaultColumnSize::title_id);
|
||||
|
||||
recent_launch_files.clear();
|
||||
auto launch_parser = parser.get("RecentLaunchFiles");
|
||||
for (auto element = launch_parser.get("Entry"); element.valid(); element = launch_parser.get("Entry", element))
|
||||
{
|
||||
const std::string path = element.value("");
|
||||
if (path.empty())
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
recent_launch_files.emplace_back(path);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "config load error: can't load recently launched game file: {}", path);
|
||||
}
|
||||
}
|
||||
|
||||
recent_nfc_files.clear();
|
||||
auto nfc_parser = parser.get("RecentNFCFiles");
|
||||
for (auto element = nfc_parser.get("Entry"); element.valid(); element = nfc_parser.get("Entry", element))
|
||||
{
|
||||
const std::string path = element.value("");
|
||||
if (path.empty())
|
||||
continue;
|
||||
try
|
||||
{
|
||||
recent_nfc_files.emplace_back(path);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "config load error: can't load recently launched nfc file: {}", path);
|
||||
}
|
||||
}
|
||||
|
||||
game_paths.clear();
|
||||
auto game_path_parser = parser.get("GamePaths");
|
||||
for (auto element = game_path_parser.get("Entry"); element.valid(); element = game_path_parser.get("Entry", element))
|
||||
|
|
@ -354,23 +268,16 @@ void CemuConfig::Load(XMLConfigParser& parser)
|
|||
dsu_client.host = dsuc.get_attribute("host", dsu_client.host);
|
||||
dsu_client.port = dsuc.get_attribute("port", dsu_client.port);
|
||||
|
||||
// hotkeys
|
||||
auto xml_hotkeys = parser.get("Hotkeys");
|
||||
hotkeys.modifiers = xml_hotkeys.get("modifiers", sHotkeyCfg{});
|
||||
hotkeys.exitFullscreen = xml_hotkeys.get("ExitFullscreen", sHotkeyCfg{uKeyboardHotkey{WXK_ESCAPE}});
|
||||
hotkeys.toggleFullscreen = xml_hotkeys.get("ToggleFullscreen", sHotkeyCfg{uKeyboardHotkey{WXK_F11}});
|
||||
hotkeys.toggleFullscreenAlt = xml_hotkeys.get("ToggleFullscreenAlt", sHotkeyCfg{uKeyboardHotkey{WXK_CONTROL_M, true}}); // ALT+ENTER
|
||||
hotkeys.takeScreenshot = xml_hotkeys.get("TakeScreenshot", sHotkeyCfg{uKeyboardHotkey{WXK_F12}});
|
||||
hotkeys.toggleFastForward = xml_hotkeys.get("ToggleFastForward", sHotkeyCfg{});
|
||||
|
||||
// emulatedusbdevices
|
||||
auto usbdevices = parser.get("EmulatedUsbDevices");
|
||||
emulated_usb_devices.emulate_skylander_portal = usbdevices.get("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal);
|
||||
emulated_usb_devices.emulate_infinity_base = usbdevices.get("EmulateInfinityBase", emulated_usb_devices.emulate_infinity_base);
|
||||
emulated_usb_devices.emulate_dimensions_toypad = usbdevices.get("EmulateDimensionsToypad", emulated_usb_devices.emulate_dimensions_toypad);
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
void CemuConfig::Save(XMLConfigParser& parser)
|
||||
XMLConfigParser CemuConfig::Save(XMLConfigParser& parser)
|
||||
{
|
||||
auto config = parser.set("content");
|
||||
// general settings
|
||||
|
|
@ -378,65 +285,12 @@ void CemuConfig::Save(XMLConfigParser& parser)
|
|||
config.set("advanced_ppc_logging", advanced_ppc_logging.GetValue());
|
||||
config.set("mlc_path", mlc_path.GetValue().c_str());
|
||||
config.set<bool>("permanent_storage", permanent_storage);
|
||||
config.set<sint32>("language", language);
|
||||
config.set<bool>("use_discord_presence", use_discord_presence);
|
||||
config.set<bool>("fullscreen_menubar", fullscreen_menubar);
|
||||
config.set<bool>("feral_gamemode", feral_gamemode);
|
||||
config.set<bool>("check_update", check_update);
|
||||
config.set<bool>("receive_untested_updates", receive_untested_updates);
|
||||
config.set<bool>("save_screenshot", save_screenshot);
|
||||
config.set<bool>("vk_warning", did_show_vulkan_warning);
|
||||
config.set<bool>("gp_download", did_show_graphic_pack_download);
|
||||
config.set<bool>("macos_disclaimer", did_show_macos_disclaimer);
|
||||
config.set<bool>("fullscreen", fullscreen);
|
||||
config.set("proxy_server", proxy_server.GetValue().c_str());
|
||||
config.set<bool>("disable_screensaver", disable_screensaver);
|
||||
config.set<bool>("play_boot_sound", play_boot_sound);
|
||||
|
||||
// config.set("cpu_mode", cpu_mode.GetValue());
|
||||
//config.set("console_region", console_region.GetValue());
|
||||
config.set("console_language", console_language.GetValue());
|
||||
|
||||
auto wpos = config.set("window_position");
|
||||
wpos.set<sint32>("x", window_position.x);
|
||||
wpos.set<sint32>("y", window_position.y);
|
||||
auto wsize = config.set("window_size");
|
||||
wsize.set<sint32>("x", window_size.x);
|
||||
wsize.set<sint32>("y", window_size.y);
|
||||
config.set<bool>("window_maximized", window_maximized);
|
||||
|
||||
config.set<bool>("open_pad", pad_open);
|
||||
auto ppos = config.set("pad_position");
|
||||
ppos.set<sint32>("x", pad_position.x);
|
||||
ppos.set<sint32>("y", pad_position.y);
|
||||
auto psize = config.set("pad_size");
|
||||
psize.set<sint32>("x", pad_size.x);
|
||||
psize.set<sint32>("y", pad_size.y);
|
||||
config.set<bool>("pad_maximized", pad_maximized);
|
||||
config.set<bool>("show_icon_column" , show_icon_column);
|
||||
|
||||
auto gamelist = config.set("GameList");
|
||||
gamelist.set("style", game_list_style);
|
||||
gamelist.set("order", game_list_column_order);
|
||||
gamelist.set("name_width", column_width.name);
|
||||
gamelist.set("version_width", column_width.version);
|
||||
gamelist.set("dlc_width", column_width.dlc);
|
||||
gamelist.set("game_time_width", column_width.game_time);
|
||||
gamelist.set("game_started_width", column_width.game_started);
|
||||
gamelist.set("region_width", column_width.region);
|
||||
gamelist.set("title_id", column_width.title_id);
|
||||
|
||||
auto launch_files_parser = config.set("RecentLaunchFiles");
|
||||
for (const auto& entry : recent_launch_files)
|
||||
{
|
||||
launch_files_parser.set("Entry", entry.c_str());
|
||||
}
|
||||
|
||||
auto nfc_files_parser = config.set("RecentNFCFiles");
|
||||
for (const auto& entry : recent_nfc_files)
|
||||
{
|
||||
nfc_files_parser.set("Entry", entry.c_str());
|
||||
}
|
||||
|
||||
// game paths
|
||||
auto game_path_parser = config.set("GamePaths");
|
||||
|
|
@ -566,20 +420,13 @@ void CemuConfig::Save(XMLConfigParser& parser)
|
|||
dsuc.set_attribute("host", dsu_client.host);
|
||||
dsuc.set_attribute("port", dsu_client.port);
|
||||
|
||||
// hotkeys
|
||||
auto xml_hotkeys = config.set("Hotkeys");
|
||||
xml_hotkeys.set("modifiers", hotkeys.modifiers);
|
||||
xml_hotkeys.set("ExitFullscreen", hotkeys.exitFullscreen);
|
||||
xml_hotkeys.set("ToggleFullscreen", hotkeys.toggleFullscreen);
|
||||
xml_hotkeys.set("ToggleFullscreenAlt", hotkeys.toggleFullscreenAlt);
|
||||
xml_hotkeys.set("TakeScreenshot", hotkeys.takeScreenshot);
|
||||
xml_hotkeys.set("ToggleFastForward", hotkeys.toggleFastForward);
|
||||
|
||||
// emulated usb devices
|
||||
auto usbdevices = config.set("EmulatedUsbDevices");
|
||||
usbdevices.set("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal.GetValue());
|
||||
usbdevices.set("EmulateInfinityBase", emulated_usb_devices.emulate_infinity_base.GetValue());
|
||||
usbdevices.set("EmulateDimensionsToypad", emulated_usb_devices.emulate_dimensions_toypad.GetValue());
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
GameEntry* CemuConfig::GetGameEntryByTitleId(uint64 titleId)
|
||||
|
|
@ -646,22 +493,6 @@ void CemuConfig::SetGameListCustomName(uint64 titleId, std::string customName)
|
|||
gameEntry->custom_name = std::move(customName);
|
||||
}
|
||||
|
||||
void CemuConfig::AddRecentlyLaunchedFile(std::string_view file)
|
||||
{
|
||||
recent_launch_files.insert(recent_launch_files.begin(), std::string(file));
|
||||
RemoveDuplicatesKeepOrder(recent_launch_files);
|
||||
while(recent_launch_files.size() > kMaxRecentEntries)
|
||||
recent_launch_files.pop_back();
|
||||
}
|
||||
|
||||
void CemuConfig::AddRecentNfcFile(std::string_view file)
|
||||
{
|
||||
recent_nfc_files.insert(recent_nfc_files.begin(), std::string(file));
|
||||
RemoveDuplicatesKeepOrder(recent_nfc_files);
|
||||
while (recent_nfc_files.size() > kMaxRecentEntries)
|
||||
recent_nfc_files.pop_back();
|
||||
}
|
||||
|
||||
NetworkService CemuConfig::GetAccountNetworkService(uint32 persistentId)
|
||||
{
|
||||
auto it = account.service_select.find(persistentId);
|
||||
|
|
|
|||
|
|
@ -5,9 +5,6 @@
|
|||
#include "util/math/vector2.h"
|
||||
#include "Cafe/Account/Account.h"
|
||||
|
||||
#include <wx/language.h>
|
||||
#include <wx/intl.h>
|
||||
|
||||
enum class NetworkService;
|
||||
|
||||
struct GameEntry
|
||||
|
|
@ -191,50 +188,6 @@ enum class CrashDump
|
|||
ENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Enabled);
|
||||
#endif
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16 key : 13; // enough bits for all keycodes
|
||||
uint16 alt : 1;
|
||||
uint16 ctrl : 1;
|
||||
uint16 shift : 1;
|
||||
};
|
||||
uint16 raw;
|
||||
} uKeyboardHotkey;
|
||||
|
||||
typedef sint16 ControllerHotkey_t;
|
||||
|
||||
struct sHotkeyCfg
|
||||
{
|
||||
static constexpr uint8 keyboardNone{WXK_NONE};
|
||||
static constexpr sint8 controllerNone{-1}; // no enums to work with, but buttons start from 0
|
||||
|
||||
uKeyboardHotkey keyboard{keyboardNone};
|
||||
ControllerHotkey_t controller{controllerNone};
|
||||
|
||||
/* for defaults */
|
||||
sHotkeyCfg(const uKeyboardHotkey& keyboard = {WXK_NONE}, const ControllerHotkey_t& controller = {-1}) :
|
||||
keyboard(keyboard), controller(controller) {};
|
||||
|
||||
/* for reading from xml */
|
||||
sHotkeyCfg(const char* xml_values)
|
||||
{
|
||||
std::istringstream iss(xml_values);
|
||||
iss >> keyboard.raw >> controller;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<sHotkeyCfg> : formatter<string_view>
|
||||
{
|
||||
template <typename FormatContext>
|
||||
auto format(const sHotkeyCfg c, FormatContext &ctx) const {
|
||||
std::string xml_values = fmt::format("{} {}", c.keyboard.raw, c.controller);
|
||||
return formatter<string_view>::format(xml_values, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<PrecompiledShaderOption> : formatter<string_view> {
|
||||
template <typename FormatContext>
|
||||
|
|
@ -305,15 +258,15 @@ struct fmt::formatter<CafeConsoleRegion> : formatter<string_view> {
|
|||
string_view name;
|
||||
switch (v)
|
||||
{
|
||||
case CafeConsoleRegion::JPN: name = wxTRANSLATE("Japan"); break;
|
||||
case CafeConsoleRegion::USA: name = wxTRANSLATE("USA"); break;
|
||||
case CafeConsoleRegion::EUR: name = wxTRANSLATE("Europe"); break;
|
||||
case CafeConsoleRegion::AUS_DEPR: name = wxTRANSLATE("Australia"); break;
|
||||
case CafeConsoleRegion::CHN: name = wxTRANSLATE("China"); break;
|
||||
case CafeConsoleRegion::KOR: name = wxTRANSLATE("Korea"); break;
|
||||
case CafeConsoleRegion::TWN: name = wxTRANSLATE("Taiwan"); break;
|
||||
case CafeConsoleRegion::Auto: name = wxTRANSLATE("Auto"); break;
|
||||
default: name = wxTRANSLATE("many"); break;
|
||||
case CafeConsoleRegion::JPN: name = TR_NOOP("Japan"); break;
|
||||
case CafeConsoleRegion::USA: name = TR_NOOP("USA"); break;
|
||||
case CafeConsoleRegion::EUR: name = TR_NOOP("Europe"); break;
|
||||
case CafeConsoleRegion::AUS_DEPR: name = TR_NOOP("Australia"); break;
|
||||
case CafeConsoleRegion::CHN: name = TR_NOOP("China"); break;
|
||||
case CafeConsoleRegion::KOR: name = TR_NOOP("Korea"); break;
|
||||
case CafeConsoleRegion::TWN: name = TR_NOOP("Taiwan"); break;
|
||||
case CafeConsoleRegion::Auto: name = TR_NOOP("Auto"); break;
|
||||
default: name = TR_NOOP("many"); break;
|
||||
|
||||
}
|
||||
return formatter<string_view>::format(name, ctx);
|
||||
|
|
@ -379,17 +332,6 @@ struct fmt::formatter<CrashDump> : formatter<string_view> {
|
|||
};
|
||||
#endif
|
||||
|
||||
namespace DefaultColumnSize {
|
||||
enum : uint32 {
|
||||
name = 500u,
|
||||
version = 60u,
|
||||
dlc = 50u,
|
||||
game_time = 140u,
|
||||
game_started = 160u,
|
||||
region = 80u,
|
||||
title_id = 160u
|
||||
};
|
||||
};
|
||||
|
||||
struct CemuConfig
|
||||
{
|
||||
|
|
@ -408,12 +350,7 @@ struct CemuConfig
|
|||
|
||||
ConfigValue<bool> permanent_storage{ true };
|
||||
|
||||
ConfigValue<sint32> language{ wxLANGUAGE_DEFAULT };
|
||||
ConfigValue<bool> use_discord_presence{ true };
|
||||
ConfigValue<std::string> mlc_path{};
|
||||
ConfigValue<bool> fullscreen_menubar{ false };
|
||||
ConfigValue<bool> fullscreen{ false };
|
||||
ConfigValue<bool> feral_gamemode{false};
|
||||
ConfigValue<std::string> proxy_server{};
|
||||
|
||||
// temporary workaround because feature crashes on macOS
|
||||
|
|
@ -444,43 +381,6 @@ struct CemuConfig
|
|||
ConfigValueBounds<CPUMode> cpu_mode{ CPUMode::Auto };
|
||||
ConfigValueBounds<CafeConsoleLanguage> console_language{ CafeConsoleLanguage::EN };
|
||||
|
||||
// max 15 entries
|
||||
static constexpr size_t kMaxRecentEntries = 15;
|
||||
std::vector<std::string> recent_launch_files;
|
||||
std::vector<std::string> recent_nfc_files;
|
||||
|
||||
Vector2i window_position{-1,-1};
|
||||
Vector2i window_size{ -1,-1 };
|
||||
ConfigValue<bool> window_maximized;
|
||||
|
||||
ConfigValue<bool> pad_open;
|
||||
Vector2i pad_position{ -1,-1 };
|
||||
Vector2i pad_size{ -1,-1 };
|
||||
ConfigValue<bool> pad_maximized;
|
||||
|
||||
ConfigValue<bool> check_update{true};
|
||||
ConfigValue<bool> receive_untested_updates{false};
|
||||
ConfigValue<bool> save_screenshot{true};
|
||||
|
||||
ConfigValue<bool> did_show_vulkan_warning{false};
|
||||
ConfigValue<bool> did_show_graphic_pack_download{false}; // no longer used but we keep the config value around in case people downgrade Cemu. Despite the name this was used for the Getting Started dialog
|
||||
ConfigValue<bool> did_show_macos_disclaimer{false};
|
||||
|
||||
ConfigValue<bool> show_icon_column{ true };
|
||||
|
||||
int game_list_style = 0;
|
||||
std::string game_list_column_order;
|
||||
struct
|
||||
{
|
||||
uint32 name = DefaultColumnSize::name;
|
||||
uint32 version = DefaultColumnSize::version;
|
||||
uint32 dlc = DefaultColumnSize::dlc;
|
||||
uint32 game_time = DefaultColumnSize::game_time;
|
||||
uint32 game_started = DefaultColumnSize::game_started;
|
||||
uint32 region = DefaultColumnSize::region;
|
||||
uint32 title_id = 0;
|
||||
} column_width{};
|
||||
|
||||
// graphics
|
||||
ConfigValue<GraphicAPI> graphic_api{ kVulkan };
|
||||
std::array<uint8, 16> graphic_device_uuid;
|
||||
|
|
@ -543,26 +443,12 @@ struct CemuConfig
|
|||
ConfigValue<uint16> port{ 26760 };
|
||||
}dsu_client{};
|
||||
|
||||
// hotkeys
|
||||
struct
|
||||
{
|
||||
sHotkeyCfg modifiers;
|
||||
sHotkeyCfg toggleFullscreen;
|
||||
sHotkeyCfg toggleFullscreenAlt;
|
||||
sHotkeyCfg exitFullscreen;
|
||||
sHotkeyCfg takeScreenshot;
|
||||
sHotkeyCfg toggleFastForward;
|
||||
} hotkeys{};
|
||||
|
||||
// debug
|
||||
ConfigValueBounds<CrashDump> crash_dump{ CrashDump::Disabled };
|
||||
ConfigValue<uint16> gdb_port{ 1337 };
|
||||
|
||||
void Load(XMLConfigParser& parser);
|
||||
void Save(XMLConfigParser& parser);
|
||||
|
||||
void AddRecentlyLaunchedFile(std::string_view file);
|
||||
void AddRecentNfcFile(std::string_view file);
|
||||
XMLConfigParser Load(XMLConfigParser& parser);
|
||||
XMLConfigParser Save(XMLConfigParser& parser);
|
||||
|
||||
bool IsGameListFavorite(uint64 titleId);
|
||||
void SetGameListFavorite(uint64 titleId, bool isFavorite);
|
||||
|
|
@ -598,8 +484,15 @@ struct CemuConfig
|
|||
GameEntry* CreateGameEntry(uint64 titleId);
|
||||
};
|
||||
|
||||
typedef XMLDataConfig<CemuConfig, &CemuConfig::Load, &CemuConfig::Save> XMLCemuConfig_t;
|
||||
extern XMLCemuConfig_t g_config;
|
||||
inline CemuConfig& GetConfig() { return g_config.data(); }
|
||||
typedef XMLDataConfig<CemuConfig> XMLCemuConfig_t;
|
||||
|
||||
inline XMLCemuConfig_t& GetConfigHandle()
|
||||
{
|
||||
static XMLCemuConfig_t config;
|
||||
return config;
|
||||
}
|
||||
|
||||
inline CemuConfig& GetConfig()
|
||||
{
|
||||
return GetConfigHandle().data();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#include "Cafe/OS/libs/coreinit/coreinit.h"
|
||||
|
||||
#include "boost/program_options.hpp"
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "config/NetworkSettings.h"
|
||||
|
|
@ -226,11 +225,7 @@ bool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)
|
|||
std::string errorMsg;
|
||||
errorMsg.append("Error while trying to parse command line parameter:\n");
|
||||
errorMsg.append(ex.what());
|
||||
#if BOOST_OS_WINDOWS
|
||||
wxMessageBox(errorMsg, "Parameter error", wxICON_ERROR);
|
||||
#else
|
||||
std::cout << errorMsg << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ struct PretendoURLs {
|
|||
inline static std::string OLVURL = "https://discovery.olv.pretendo.cc/v1/endpoint";
|
||||
};
|
||||
|
||||
typedef XMLDataConfig<NetworkConfig, &NetworkConfig::Load, &NetworkConfig::Save> XMLNetworkConfig_t;
|
||||
typedef XMLDataConfig<NetworkConfig> XMLNetworkConfig_t;
|
||||
extern XMLNetworkConfig_t n_config;
|
||||
inline NetworkConfig& GetNetworkConfig() { return n_config.data();};
|
||||
|
||||
|
|
|
|||
|
|
@ -320,7 +320,15 @@ private:
|
|||
bool m_is_root;
|
||||
};
|
||||
|
||||
template <typename T, void(T::*L)(XMLConfigParser&) = nullptr, void(T::*S)(XMLConfigParser&) = nullptr>
|
||||
using ChildXMLConfigParser = std::pair<std::function<void(XMLConfigParser&)>, std::function<void(XMLConfigParser&)>>;
|
||||
|
||||
template<typename T>
|
||||
concept XMLConfigurable = requires(T t, XMLConfigParser& configParser) {
|
||||
{ t.Save(configParser) } -> std::same_as<XMLConfigParser>;
|
||||
{ t.Load(configParser) } -> std::same_as<XMLConfigParser>;
|
||||
};
|
||||
|
||||
template <XMLConfigurable T>
|
||||
class XMLConfig
|
||||
{
|
||||
public:
|
||||
|
|
@ -339,9 +347,6 @@ public:
|
|||
|
||||
bool Load()
|
||||
{
|
||||
if (L == nullptr)
|
||||
return false;
|
||||
|
||||
if (m_filename.empty())
|
||||
return false;
|
||||
|
||||
|
|
@ -350,8 +355,6 @@ public:
|
|||
|
||||
bool Load(const std::wstring& filename)
|
||||
{
|
||||
if (L == nullptr)
|
||||
return false;
|
||||
FileStream* fs = FileStream::openFile(filename.c_str());
|
||||
if (!fs)
|
||||
{
|
||||
|
|
@ -370,19 +373,23 @@ public:
|
|||
{
|
||||
cemuLog_logDebug(LogType::Force, "XMLConfig::Load > LoadFile {}", error);
|
||||
}
|
||||
if (success)
|
||||
|
||||
if (!success)
|
||||
{
|
||||
auto parser = XMLConfigParser(&doc);
|
||||
(m_instance.*L)(parser);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto parser = XMLConfigParser(&doc);
|
||||
auto parentParser = m_instance.Load(parser);
|
||||
|
||||
for (auto [save, load] : m_childConfigParsers)
|
||||
load(parentParser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Save()
|
||||
{
|
||||
if (S == nullptr)
|
||||
return false;
|
||||
|
||||
if (m_filename.empty())
|
||||
return false;
|
||||
|
||||
|
|
@ -391,9 +398,6 @@ public:
|
|||
|
||||
bool Save(const std::wstring& filename)
|
||||
{
|
||||
if (S == nullptr)
|
||||
return false;
|
||||
|
||||
std::wstring tmp_name = fmt::format(L"{}_{}.tmp", filename,rand() % 1000);
|
||||
std::error_code err;
|
||||
fs::create_directories(fs::path(filename).parent_path(), err);
|
||||
|
|
@ -420,7 +424,10 @@ public:
|
|||
doc.InsertFirstChild(declaration);
|
||||
|
||||
auto parser = XMLConfigParser(&doc);
|
||||
(m_instance.*S)(parser);
|
||||
auto parentParser = m_instance.Save(parser);
|
||||
|
||||
for (auto [save, load] : m_childConfigParsers)
|
||||
save(parentParser);
|
||||
|
||||
const tinyxml2::XMLError error = doc.SaveFile(file);
|
||||
const bool success = error == tinyxml2::XML_SUCCESS;
|
||||
|
|
@ -445,24 +452,96 @@ public:
|
|||
|
||||
std::unique_lock<std::mutex> Lock() { return std::unique_lock(m_mutex); }
|
||||
|
||||
private:
|
||||
void AddChildConfig(ChildXMLConfigParser childConfigParser)
|
||||
{
|
||||
m_childConfigParsers.push_back(childConfigParser);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<ChildXMLConfigParser> m_childConfigParsers;
|
||||
T& m_instance;
|
||||
std::wstring m_filename;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
template <typename T, void(T::*L)(XMLConfigParser&), void(T::*S)(XMLConfigParser&)>
|
||||
class XMLDataConfig : public XMLConfig<T, L, S>
|
||||
template<typename T>
|
||||
concept XMLConfigProvider = requires(T t, ChildXMLConfigParser& configParser) {
|
||||
{ t().Save() } -> std::same_as<bool>;
|
||||
{ t().Load() } -> std::same_as<bool>;
|
||||
{ t().Lock() } -> std::same_as<std::unique_lock<std::mutex>>;
|
||||
{ t().AddChildConfig(configParser) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
template<typename T, void (T::*L)(XMLConfigParser&), void (T::*S)(XMLConfigParser&)>
|
||||
class XMLChildConfig
|
||||
{
|
||||
public:
|
||||
XMLChildConfig(XMLConfigProvider auto getParentConfig)
|
||||
{
|
||||
m_parentConfig = {
|
||||
.lock = [getParentConfig]() { return getParentConfig().Lock(); },
|
||||
.save = [getParentConfig]() { return getParentConfig().Load(); },
|
||||
.load = [getParentConfig]() { return getParentConfig().Save(); },
|
||||
};
|
||||
|
||||
auto configParser = std::make_pair(
|
||||
[this](XMLConfigParser& parser) {
|
||||
(m_data.*S)(parser);
|
||||
},
|
||||
[this](XMLConfigParser& parser) {
|
||||
(m_data.*L)(parser);
|
||||
});
|
||||
|
||||
getParentConfig().AddChildConfig(configParser);
|
||||
}
|
||||
|
||||
bool Save()
|
||||
{
|
||||
return m_parentConfig.save();
|
||||
}
|
||||
|
||||
bool Load()
|
||||
{
|
||||
return m_parentConfig.load();
|
||||
}
|
||||
|
||||
T& Data()
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> Lock()
|
||||
{
|
||||
return m_parentConfig.lock();
|
||||
}
|
||||
|
||||
virtual ~XMLChildConfig() = default;
|
||||
|
||||
private:
|
||||
T m_data;
|
||||
struct
|
||||
{
|
||||
std::function<std::unique_lock<std::mutex>()> lock;
|
||||
std::function<bool()> save;
|
||||
std::function<bool()> load;
|
||||
} m_parentConfig;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct XMLDataConfig {};
|
||||
|
||||
template <XMLConfigurable T>
|
||||
class XMLDataConfig<T> : public XMLConfig<T>
|
||||
{
|
||||
public:
|
||||
XMLDataConfig()
|
||||
: XMLConfig<T, L, S>::XMLConfig(m_data), m_data() {}
|
||||
: XMLConfig<T>::XMLConfig(m_data), m_data() {}
|
||||
|
||||
XMLDataConfig(std::wstring_view filename)
|
||||
: XMLConfig<T, L, S>::XMLConfig(m_data, filename), m_data() {}
|
||||
: XMLConfig<T>::XMLConfig(m_data, filename), m_data() {}
|
||||
|
||||
XMLDataConfig(std::wstring_view filename, T init_data)
|
||||
: XMLConfig<T, L, S>::XMLConfig(m_data, filename), m_data(std::move(init_data)) {}
|
||||
: XMLConfig<T>::XMLConfig(m_data, filename), m_data(std::move(init_data)) {}
|
||||
|
||||
XMLDataConfig(const XMLDataConfig& o) = delete;
|
||||
|
||||
|
|
@ -471,3 +550,51 @@ public:
|
|||
private:
|
||||
T m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept XMLStandaloneConfigurable = requires(T t, XMLConfigParser& configParser) {
|
||||
{ t.Save(configParser) } -> std::same_as<void>;
|
||||
{ t.Load(configParser) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
template<XMLStandaloneConfigurable T>
|
||||
struct XMLConfigWrapper
|
||||
{
|
||||
XMLConfigParser Save(XMLConfigParser& configParser)
|
||||
{
|
||||
data.Save(configParser);
|
||||
return configParser;
|
||||
}
|
||||
|
||||
XMLConfigParser Load(XMLConfigParser& configParser)
|
||||
{
|
||||
data.Load(configParser);
|
||||
return configParser;
|
||||
}
|
||||
|
||||
T data;
|
||||
};
|
||||
|
||||
template<XMLStandaloneConfigurable T>
|
||||
class XMLDataConfig<T> : public XMLConfig<XMLConfigWrapper<T>>
|
||||
{
|
||||
public:
|
||||
XMLDataConfig()
|
||||
: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper), m_configWrapper() {}
|
||||
|
||||
XMLDataConfig(std::wstring_view filename)
|
||||
: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper, filename), m_configWrapper() {}
|
||||
|
||||
XMLDataConfig(std::wstring_view filename, T init_data)
|
||||
: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper, filename), m_configWrapper{.data = std::move(init_data)} {}
|
||||
|
||||
XMLDataConfig(const XMLDataConfig& o) = delete;
|
||||
|
||||
T& data()
|
||||
{
|
||||
return m_configWrapper.data;
|
||||
}
|
||||
|
||||
private:
|
||||
XMLConfigWrapper<T> m_configWrapper;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue