mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-25 18:46:55 +01:00
Windows default to non-portable + Reworked MLC handling and related UI (#1252)
This commit is contained in:
parent
7522c8470e
commit
64232ffdbd
@ -7,41 +7,47 @@
|
|||||||
#include "config/LaunchSettings.h"
|
#include "config/LaunchSettings.h"
|
||||||
#include "util/helpers/helpers.h"
|
#include "util/helpers/helpers.h"
|
||||||
|
|
||||||
std::set<fs::path>
|
void ActiveSettings::SetPaths(bool isPortableMode,
|
||||||
ActiveSettings::LoadOnce(
|
|
||||||
const fs::path& executablePath,
|
const fs::path& executablePath,
|
||||||
const fs::path& userDataPath,
|
const fs::path& userDataPath,
|
||||||
const fs::path& configPath,
|
const fs::path& configPath,
|
||||||
const fs::path& cachePath,
|
const fs::path& cachePath,
|
||||||
const fs::path& dataPath)
|
const fs::path& dataPath,
|
||||||
|
std::set<fs::path>& failedWriteAccess)
|
||||||
{
|
{
|
||||||
|
cemu_assert_debug(!s_setPathsCalled); // can only change paths before loading
|
||||||
|
s_isPortableMode = isPortableMode;
|
||||||
s_executable_path = executablePath;
|
s_executable_path = executablePath;
|
||||||
s_user_data_path = userDataPath;
|
s_user_data_path = userDataPath;
|
||||||
s_config_path = configPath;
|
s_config_path = configPath;
|
||||||
s_cache_path = cachePath;
|
s_cache_path = cachePath;
|
||||||
s_data_path = dataPath;
|
s_data_path = dataPath;
|
||||||
std::set<fs::path> failed_write_access;
|
failedWriteAccess.clear();
|
||||||
for (auto&& path : {userDataPath, configPath, cachePath})
|
for (auto&& path : {userDataPath, configPath, cachePath})
|
||||||
{
|
|
||||||
if (!fs::exists(path))
|
|
||||||
{
|
{
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
if (!fs::exists(path, ec))
|
||||||
fs::create_directories(path, ec);
|
fs::create_directories(path, ec);
|
||||||
}
|
|
||||||
if (!TestWriteAccess(path))
|
if (!TestWriteAccess(path))
|
||||||
{
|
{
|
||||||
cemuLog_log(LogType::Force, "Failed to write to {}", _pathToUtf8(path));
|
cemuLog_log(LogType::Force, "Failed to write to {}", _pathToUtf8(path));
|
||||||
failed_write_access.insert(path);
|
failedWriteAccess.insert(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s_executable_filename = s_executable_path.filename();
|
s_executable_filename = s_executable_path.filename();
|
||||||
|
s_setPathsCalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
g_config.SetFilename(GetConfigPath("settings.xml").generic_wstring());
|
[[nodiscard]] bool ActiveSettings::IsPortableMode()
|
||||||
g_config.Load();
|
{
|
||||||
|
return s_isPortableMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActiveSettings::Init()
|
||||||
|
{
|
||||||
|
cemu_assert_debug(s_setPathsCalled);
|
||||||
std::string additionalErrorInfo;
|
std::string additionalErrorInfo;
|
||||||
s_has_required_online_files = iosuCrypt_checkRequirementsForOnlineMode(additionalErrorInfo) == IOS_CRYPTO_ONLINE_REQ_OK;
|
s_has_required_online_files = iosuCrypt_checkRequirementsForOnlineMode(additionalErrorInfo) == IOS_CRYPTO_ONLINE_REQ_OK;
|
||||||
return failed_write_access;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ActiveSettings::LoadSharedLibrariesEnabled()
|
bool ActiveSettings::LoadSharedLibrariesEnabled()
|
||||||
@ -229,6 +235,7 @@ bool ActiveSettings::ForceSamplerRoundToPrecision()
|
|||||||
|
|
||||||
fs::path ActiveSettings::GetMlcPath()
|
fs::path ActiveSettings::GetMlcPath()
|
||||||
{
|
{
|
||||||
|
cemu_assert_debug(s_setPathsCalled);
|
||||||
if(const auto launch_mlc = LaunchSettings::GetMLCPath(); launch_mlc.has_value())
|
if(const auto launch_mlc = LaunchSettings::GetMLCPath(); launch_mlc.has_value())
|
||||||
return launch_mlc.value();
|
return launch_mlc.value();
|
||||||
|
|
||||||
@ -238,6 +245,17 @@ fs::path ActiveSettings::GetMlcPath()
|
|||||||
return GetDefaultMLCPath();
|
return GetDefaultMLCPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ActiveSettings::IsCustomMlcPath()
|
||||||
|
{
|
||||||
|
cemu_assert_debug(s_setPathsCalled);
|
||||||
|
return !GetConfig().mlc_path.GetValue().empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActiveSettings::IsCommandLineMlcPath()
|
||||||
|
{
|
||||||
|
return LaunchSettings::GetMLCPath().has_value();
|
||||||
|
}
|
||||||
|
|
||||||
fs::path ActiveSettings::GetDefaultMLCPath()
|
fs::path ActiveSettings::GetDefaultMLCPath()
|
||||||
{
|
{
|
||||||
return GetUserDataPath("mlc01");
|
return GetUserDataPath("mlc01");
|
||||||
|
@ -34,12 +34,16 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Set directories and return all directories that failed write access test
|
// Set directories and return all directories that failed write access test
|
||||||
static std::set<fs::path>
|
static void
|
||||||
LoadOnce(const fs::path& executablePath,
|
SetPaths(bool isPortableMode,
|
||||||
|
const fs::path& executablePath,
|
||||||
const fs::path& userDataPath,
|
const fs::path& userDataPath,
|
||||||
const fs::path& configPath,
|
const fs::path& configPath,
|
||||||
const fs::path& cachePath,
|
const fs::path& cachePath,
|
||||||
const fs::path& dataPath);
|
const fs::path& dataPath,
|
||||||
|
std::set<fs::path>& failedWriteAccess);
|
||||||
|
|
||||||
|
static void Init();
|
||||||
|
|
||||||
[[nodiscard]] static fs::path GetExecutablePath() { return s_executable_path; }
|
[[nodiscard]] static fs::path GetExecutablePath() { return s_executable_path; }
|
||||||
[[nodiscard]] static fs::path GetExecutableFilename() { return s_executable_filename; }
|
[[nodiscard]] static fs::path GetExecutableFilename() { return s_executable_filename; }
|
||||||
@ -56,11 +60,14 @@ public:
|
|||||||
|
|
||||||
template <typename ...TArgs>
|
template <typename ...TArgs>
|
||||||
[[nodiscard]] static fs::path GetMlcPath(TArgs&&... args){ return GetPath(GetMlcPath(), std::forward<TArgs>(args)...); };
|
[[nodiscard]] static fs::path GetMlcPath(TArgs&&... args){ return GetPath(GetMlcPath(), std::forward<TArgs>(args)...); };
|
||||||
|
static bool IsCustomMlcPath();
|
||||||
|
static bool IsCommandLineMlcPath();
|
||||||
|
|
||||||
// get mlc path to default cemu root dir/mlc01
|
// get mlc path to default cemu root dir/mlc01
|
||||||
[[nodiscard]] static fs::path GetDefaultMLCPath();
|
[[nodiscard]] static fs::path GetDefaultMLCPath();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
inline static bool s_isPortableMode{false};
|
||||||
inline static fs::path s_executable_path;
|
inline static fs::path s_executable_path;
|
||||||
inline static fs::path s_user_data_path;
|
inline static fs::path s_user_data_path;
|
||||||
inline static fs::path s_config_path;
|
inline static fs::path s_config_path;
|
||||||
@ -70,6 +77,9 @@ private:
|
|||||||
inline static fs::path s_mlc_path;
|
inline static fs::path s_mlc_path;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// can be called before Init
|
||||||
|
[[nodiscard]] static bool IsPortableMode();
|
||||||
|
|
||||||
// general
|
// general
|
||||||
[[nodiscard]] static bool LoadSharedLibrariesEnabled();
|
[[nodiscard]] static bool LoadSharedLibrariesEnabled();
|
||||||
[[nodiscard]] static bool DisplayDRCEnabled();
|
[[nodiscard]] static bool DisplayDRCEnabled();
|
||||||
@ -111,6 +121,7 @@ public:
|
|||||||
[[nodiscard]] static bool ForceSamplerRoundToPrecision();
|
[[nodiscard]] static bool ForceSamplerRoundToPrecision();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
inline static bool s_setPathsCalled = false;
|
||||||
// dump options
|
// dump options
|
||||||
inline static bool s_dump_shaders = false;
|
inline static bool s_dump_shaders = false;
|
||||||
inline static bool s_dump_textures = false;
|
inline static bool s_dump_textures = false;
|
||||||
|
@ -8,10 +8,6 @@ add_library(CemuConfig
|
|||||||
LaunchSettings.h
|
LaunchSettings.h
|
||||||
NetworkSettings.cpp
|
NetworkSettings.cpp
|
||||||
NetworkSettings.h
|
NetworkSettings.h
|
||||||
PermanentConfig.cpp
|
|
||||||
PermanentConfig.h
|
|
||||||
PermanentStorage.cpp
|
|
||||||
PermanentStorage.h
|
|
||||||
XMLConfig.h
|
XMLConfig.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include <wx/language.h>
|
#include <wx/language.h>
|
||||||
|
|
||||||
#include "PermanentConfig.h"
|
|
||||||
#include "ActiveSettings.h"
|
#include "ActiveSettings.h"
|
||||||
|
|
||||||
XMLCemuConfig_t g_config(L"settings.xml");
|
XMLCemuConfig_t g_config(L"settings.xml");
|
||||||
@ -15,23 +14,6 @@ void CemuConfig::SetMLCPath(fs::path path, bool save)
|
|||||||
mlc_path.SetValue(_pathToUtf8(path));
|
mlc_path.SetValue(_pathToUtf8(path));
|
||||||
if(save)
|
if(save)
|
||||||
g_config.Save();
|
g_config.Save();
|
||||||
|
|
||||||
// if custom mlc path has been selected, store it in permanent config
|
|
||||||
if (path != ActiveSettings::GetDefaultMLCPath())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto pconfig = PermanentConfig::Load();
|
|
||||||
pconfig.custom_mlc_path = _pathToUtf8(path);
|
|
||||||
pconfig.Store();
|
|
||||||
}
|
|
||||||
catch (const PSDisabledException&) {}
|
|
||||||
catch (const std::exception& ex)
|
|
||||||
{
|
|
||||||
cemuLog_log(LogType::Force, "can't store custom mlc path in permanent storage: {}", ex.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Account::RefreshAccounts();
|
Account::RefreshAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +417,7 @@ struct CemuConfig
|
|||||||
ConfigValue<bool> save_screenshot{true};
|
ConfigValue<bool> save_screenshot{true};
|
||||||
|
|
||||||
ConfigValue<bool> did_show_vulkan_warning{false};
|
ConfigValue<bool> did_show_vulkan_warning{false};
|
||||||
ConfigValue<bool> did_show_graphic_pack_download{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> did_show_macos_disclaimer{false};
|
||||||
|
|
||||||
ConfigValue<bool> show_icon_column{ true };
|
ConfigValue<bool> show_icon_column{ true };
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
#include "PermanentConfig.h"
|
|
||||||
|
|
||||||
#include "pugixml.hpp"
|
|
||||||
|
|
||||||
#include "PermanentStorage.h"
|
|
||||||
|
|
||||||
struct xml_string_writer : pugi::xml_writer
|
|
||||||
{
|
|
||||||
std::string result;
|
|
||||||
|
|
||||||
void write(const void* data, size_t size) override
|
|
||||||
{
|
|
||||||
result.append(static_cast<const char*>(data), size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string PermanentConfig::ToXMLString() const noexcept
|
|
||||||
{
|
|
||||||
pugi::xml_document doc;
|
|
||||||
doc.append_child(pugi::node_declaration).append_attribute("encoding") = "UTF-8";
|
|
||||||
auto root = doc.append_child("config");
|
|
||||||
root.append_child("MlcPath").text().set(this->custom_mlc_path.c_str());
|
|
||||||
|
|
||||||
xml_string_writer writer;
|
|
||||||
doc.save(writer);
|
|
||||||
return writer.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PermanentConfig PermanentConfig::FromXMLString(std::string_view str) noexcept
|
|
||||||
{
|
|
||||||
PermanentConfig result{};
|
|
||||||
|
|
||||||
pugi::xml_document doc;
|
|
||||||
if(doc.load_buffer(str.data(), str.size()))
|
|
||||||
{
|
|
||||||
result.custom_mlc_path = doc.select_node("/config/MlcPath").node().text().as_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PermanentConfig PermanentConfig::Load()
|
|
||||||
{
|
|
||||||
PermanentStorage storage;
|
|
||||||
|
|
||||||
const auto str = storage.ReadFile(kFileName);
|
|
||||||
if (!str.empty())
|
|
||||||
return FromXMLString(str);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PermanentConfig::Store() noexcept
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PermanentStorage storage;
|
|
||||||
storage.WriteStringToFile(kFileName, ToXMLString());
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "PermanentStorage.h"
|
|
||||||
|
|
||||||
struct PermanentConfig
|
|
||||||
{
|
|
||||||
static constexpr const char* kFileName = "perm_setting.xml";
|
|
||||||
|
|
||||||
std::string custom_mlc_path;
|
|
||||||
|
|
||||||
[[nodiscard]] std::string ToXMLString() const noexcept;
|
|
||||||
static PermanentConfig FromXMLString(std::string_view str) noexcept;
|
|
||||||
|
|
||||||
// gets from permanent storage
|
|
||||||
static PermanentConfig Load();
|
|
||||||
// saves to permanent storage
|
|
||||||
bool Store() noexcept;
|
|
||||||
};
|
|
@ -1,76 +0,0 @@
|
|||||||
#include "PermanentStorage.h"
|
|
||||||
#include "config/CemuConfig.h"
|
|
||||||
#include "util/helpers/SystemException.h"
|
|
||||||
|
|
||||||
PermanentStorage::PermanentStorage()
|
|
||||||
{
|
|
||||||
if (!GetConfig().permanent_storage)
|
|
||||||
throw PSDisabledException();
|
|
||||||
|
|
||||||
const char* appdata = std::getenv("LOCALAPPDATA");
|
|
||||||
if (!appdata)
|
|
||||||
throw std::runtime_error("can't get LOCALAPPDATA");
|
|
||||||
m_storage_path = appdata;
|
|
||||||
m_storage_path /= "Cemu";
|
|
||||||
|
|
||||||
fs::create_directories(m_storage_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
PermanentStorage::~PermanentStorage()
|
|
||||||
{
|
|
||||||
if (m_remove_storage)
|
|
||||||
{
|
|
||||||
std::error_code ec;
|
|
||||||
fs::remove_all(m_storage_path, ec);
|
|
||||||
if (ec)
|
|
||||||
{
|
|
||||||
SystemException ex(ec);
|
|
||||||
cemuLog_log(LogType::Force, "can't remove permanent storage: {}", ex.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PermanentStorage::ClearAllFiles() const
|
|
||||||
{
|
|
||||||
fs::remove_all(m_storage_path);
|
|
||||||
fs::create_directories(m_storage_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PermanentStorage::RemoveStorage()
|
|
||||||
{
|
|
||||||
m_remove_storage = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PermanentStorage::WriteStringToFile(std::string_view filename, std::string_view content)
|
|
||||||
{
|
|
||||||
const auto name = m_storage_path.append(filename.data(), filename.data() + filename.size());
|
|
||||||
std::ofstream file(name.string());
|
|
||||||
file.write(content.data(), (uint32_t)content.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string PermanentStorage::ReadFile(std::string_view filename) noexcept
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const auto name = m_storage_path.append(filename.data(), filename.data() + filename.size());
|
|
||||||
std::ifstream file(name, std::ios::in | std::ios::ate);
|
|
||||||
if (!file.is_open())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
const auto end = file.tellg();
|
|
||||||
file.seekg(0, std::ios::beg);
|
|
||||||
const auto file_size = end - file.tellg();
|
|
||||||
if (file_size == 0)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::string result;
|
|
||||||
result.resize(file_size);
|
|
||||||
file.read(result.data(), file_size);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// disabled by config
|
|
||||||
class PSDisabledException : public std::runtime_error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PSDisabledException()
|
|
||||||
: std::runtime_error("permanent storage is disabled by user") {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PermanentStorage
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PermanentStorage();
|
|
||||||
~PermanentStorage();
|
|
||||||
|
|
||||||
void ClearAllFiles() const;
|
|
||||||
// flags storage to be removed on destruction
|
|
||||||
void RemoveStorage();
|
|
||||||
|
|
||||||
void WriteStringToFile(std::string_view filename, std::string_view content);
|
|
||||||
std::string ReadFile(std::string_view filename) noexcept;
|
|
||||||
|
|
||||||
private:
|
|
||||||
fs::path m_storage_path;
|
|
||||||
bool m_remove_storage = false;
|
|
||||||
};
|
|
@ -3,11 +3,11 @@
|
|||||||
#include "gui/wxgui.h"
|
#include "gui/wxgui.h"
|
||||||
#include "config/CemuConfig.h"
|
#include "config/CemuConfig.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
||||||
|
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
|
||||||
#include "gui/guiWrapper.h"
|
#include "gui/guiWrapper.h"
|
||||||
#include "config/ActiveSettings.h"
|
#include "config/ActiveSettings.h"
|
||||||
|
#include "config/LaunchSettings.h"
|
||||||
#include "gui/GettingStartedDialog.h"
|
#include "gui/GettingStartedDialog.h"
|
||||||
#include "config/PermanentConfig.h"
|
|
||||||
#include "config/PermanentStorage.h"
|
|
||||||
#include "input/InputManager.h"
|
#include "input/InputManager.h"
|
||||||
#include "gui/helpers/wxHelpers.h"
|
#include "gui/helpers/wxHelpers.h"
|
||||||
#include "Cemu/ncrypto/ncrypto.h"
|
#include "Cemu/ncrypto/ncrypto.h"
|
||||||
@ -30,7 +30,10 @@ wxIMPLEMENT_APP_NO_MAIN(CemuApp);
|
|||||||
extern WindowInfo g_window_info;
|
extern WindowInfo g_window_info;
|
||||||
extern std::shared_mutex g_mutex;
|
extern std::shared_mutex g_mutex;
|
||||||
|
|
||||||
int mainEmulatorHLE();
|
// forward declarations from main.cpp
|
||||||
|
void UnitTests();
|
||||||
|
void CemuCommonInit();
|
||||||
|
|
||||||
void HandlePostUpdate();
|
void HandlePostUpdate();
|
||||||
// Translation strings to extract for gettext:
|
// Translation strings to extract for gettext:
|
||||||
void unused_translation_dummy()
|
void unused_translation_dummy()
|
||||||
@ -54,34 +57,86 @@ void unused_translation_dummy()
|
|||||||
void(_("unknown"));
|
void(_("unknown"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CemuApp::OnInit()
|
#if BOOST_OS_WINDOWS
|
||||||
|
#include <shlobj_core.h>
|
||||||
|
fs::path GetAppDataRoamingPath()
|
||||||
{
|
{
|
||||||
|
PWSTR path = nullptr;
|
||||||
|
HRESULT result = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &path);
|
||||||
|
if (result != S_OK || !path)
|
||||||
|
{
|
||||||
|
if (path)
|
||||||
|
CoTaskMemFree(path);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::string appDataPath = boost::nowide::narrow(path);
|
||||||
|
CoTaskMemFree(path);
|
||||||
|
return _utf8ToPath(appDataPath);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOOST_OS_WINDOWS
|
||||||
|
void CemuApp::DeterminePaths(std::set<fs::path>& failedWriteAccess) // for Windows
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
bool isPortable = false;
|
||||||
fs::path user_data_path, config_path, cache_path, data_path;
|
fs::path user_data_path, config_path, cache_path, data_path;
|
||||||
auto standardPaths = wxStandardPaths::Get();
|
auto standardPaths = wxStandardPaths::Get();
|
||||||
fs::path exePath(wxHelper::MakeFSPath(standardPaths.GetExecutablePath()));
|
fs::path exePath(wxHelper::MakeFSPath(standardPaths.GetExecutablePath()));
|
||||||
|
fs::path portablePath = exePath.parent_path() / "portable";
|
||||||
|
data_path = exePath.parent_path(); // the data path is always the same as the exe path
|
||||||
|
if (fs::exists(portablePath, ec))
|
||||||
|
{
|
||||||
|
isPortable = true;
|
||||||
|
user_data_path = config_path = cache_path = portablePath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fs::path roamingPath = GetAppDataRoamingPath() / "Cemu";
|
||||||
|
user_data_path = config_path = cache_path = roamingPath;
|
||||||
|
}
|
||||||
|
// on Windows Cemu used to be portable by default prior to 2.0-89
|
||||||
|
// to remain backwards compatible with old installations we check for settings.xml in the Cemu directory
|
||||||
|
// if it exists, we use the exe path as the portable directory
|
||||||
|
if(!isPortable) // lower priority than portable directory
|
||||||
|
{
|
||||||
|
if (fs::exists(exePath.parent_path() / "settings.xml", ec))
|
||||||
|
{
|
||||||
|
isPortable = true;
|
||||||
|
user_data_path = config_path = cache_path = exePath.parent_path();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSettings::SetPaths(isPortable, exePath, user_data_path, config_path, cache_path, data_path, failedWriteAccess);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if BOOST_OS_LINUX
|
#if BOOST_OS_LINUX
|
||||||
|
void CemuApp::DeterminePaths(std::set<fs::path>& failedWriteAccess) // for Linux
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
bool isPortable = false;
|
||||||
|
fs::path user_data_path, config_path, cache_path, data_path;
|
||||||
|
auto standardPaths = wxStandardPaths::Get();
|
||||||
|
fs::path exePath(wxHelper::MakeFSPath(standardPaths.GetExecutablePath()));
|
||||||
|
fs::path portablePath = exePath.parent_path() / "portable";
|
||||||
// GetExecutablePath returns the AppImage's temporary mount location
|
// GetExecutablePath returns the AppImage's temporary mount location
|
||||||
wxString appImagePath;
|
wxString appImagePath;
|
||||||
if (wxGetEnv(("APPIMAGE"), &appImagePath))
|
if (wxGetEnv(("APPIMAGE"), &appImagePath))
|
||||||
exePath = wxHelper::MakeFSPath(appImagePath);
|
|
||||||
#endif
|
|
||||||
// Try a portable path first, if it exists.
|
|
||||||
user_data_path = config_path = cache_path = data_path = exePath.parent_path() / "portable";
|
|
||||||
#if BOOST_OS_MACOS
|
|
||||||
// If run from an app bundle, use its parent directory.
|
|
||||||
fs::path appPath = exePath.parent_path().parent_path().parent_path();
|
|
||||||
if (appPath.extension() == ".app")
|
|
||||||
user_data_path = config_path = cache_path = data_path = appPath.parent_path() / "portable";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!fs::exists(user_data_path))
|
|
||||||
{
|
{
|
||||||
#if BOOST_OS_WINDOWS
|
exePath = wxHelper::MakeFSPath(appImagePath);
|
||||||
user_data_path = config_path = cache_path = data_path = exePath.parent_path();
|
portablePath = exePath.parent_path() / "portable";
|
||||||
#else
|
}
|
||||||
|
if (fs::exists(portablePath, ec))
|
||||||
|
{
|
||||||
|
isPortable = true;
|
||||||
|
user_data_path = config_path = cache_path = portablePath;
|
||||||
|
// in portable mode assume the data directories (resources, gameProfiles/default/) are next to the executable
|
||||||
|
data_path = exePath.parent_path();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
SetAppName("Cemu");
|
SetAppName("Cemu");
|
||||||
wxString appName=GetAppName();
|
wxString appName = GetAppName();
|
||||||
#if BOOST_OS_LINUX
|
|
||||||
standardPaths.SetFileLayout(wxStandardPaths::FileLayout::FileLayout_XDG);
|
standardPaths.SetFileLayout(wxStandardPaths::FileLayout::FileLayout_XDG);
|
||||||
auto getEnvDir = [&](const wxString& varName, const wxString& defaultValue)
|
auto getEnvDir = [&](const wxString& varName, const wxString& defaultValue)
|
||||||
{
|
{
|
||||||
@ -90,33 +145,151 @@ bool CemuApp::OnInit()
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
return dir;
|
return dir;
|
||||||
};
|
};
|
||||||
wxString homeDir=wxFileName::GetHomeDir();
|
wxString homeDir = wxFileName::GetHomeDir();
|
||||||
user_data_path = (getEnvDir(wxS("XDG_DATA_HOME"), homeDir + wxS("/.local/share")) + "/" + appName).ToStdString();
|
user_data_path = (getEnvDir(wxS("XDG_DATA_HOME"), homeDir + wxS("/.local/share")) + "/" + appName).ToStdString();
|
||||||
config_path = (getEnvDir(wxS("XDG_CONFIG_HOME"), homeDir + wxS("/.config")) + "/" + appName).ToStdString();
|
config_path = (getEnvDir(wxS("XDG_CONFIG_HOME"), homeDir + wxS("/.config")) + "/" + appName).ToStdString();
|
||||||
#else
|
|
||||||
user_data_path = config_path = standardPaths.GetUserDataDir().ToStdString();
|
|
||||||
#endif
|
|
||||||
data_path = standardPaths.GetDataDir().ToStdString();
|
data_path = standardPaths.GetDataDir().ToStdString();
|
||||||
cache_path = standardPaths.GetUserDir(wxStandardPaths::Dir::Dir_Cache).ToStdString();
|
cache_path = standardPaths.GetUserDir(wxStandardPaths::Dir::Dir_Cache).ToStdString();
|
||||||
cache_path /= appName.ToStdString();
|
cache_path /= appName.ToStdString();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
ActiveSettings::SetPaths(isPortable, exePath, user_data_path, config_path, cache_path, data_path, failedWriteAccess);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
auto failed_write_access = ActiveSettings::LoadOnce(exePath, user_data_path, config_path, cache_path, data_path);
|
#if BOOST_OS_MACOS
|
||||||
for (auto&& path : failed_write_access)
|
void CemuApp::DeterminePaths(std::set<fs::path>& failedWriteAccess) // for MacOS
|
||||||
wxMessageBox(formatWxString(_("Cemu can't write to {}!"), wxString::FromUTF8(_pathToUtf8(path))),
|
{
|
||||||
_("Warning"), wxOK | wxCENTRE | wxICON_EXCLAMATION, nullptr);
|
std::error_code ec;
|
||||||
|
bool isPortable = false;
|
||||||
|
fs::path user_data_path, config_path, cache_path, data_path;
|
||||||
|
auto standardPaths = wxStandardPaths::Get();
|
||||||
|
fs::path exePath(wxHelper::MakeFSPath(standardPaths.GetExecutablePath()));
|
||||||
|
// If run from an app bundle, use its parent directory
|
||||||
|
fs::path appPath = exePath.parent_path().parent_path().parent_path();
|
||||||
|
fs::path portablePath = appPath.extension() == ".app" ? appPath.parent_path() / "portable" : exePath.parent_path() / "portable";
|
||||||
|
if (fs::exists(portablePath, ec))
|
||||||
|
{
|
||||||
|
isPortable = true;
|
||||||
|
user_data_path = config_path = cache_path = portablePath;
|
||||||
|
data_path = exePath.parent_path();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetAppName("Cemu");
|
||||||
|
wxString appName = GetAppName();
|
||||||
|
user_data_path = config_path = standardPaths.GetUserDataDir().ToStdString();
|
||||||
|
data_path = standardPaths.GetDataDir().ToStdString();
|
||||||
|
cache_path = standardPaths.GetUserDir(wxStandardPaths::Dir::Dir_Cache).ToStdString();
|
||||||
|
cache_path /= appName.ToStdString();
|
||||||
|
}
|
||||||
|
ActiveSettings::SetPaths(isPortable, exePath, user_data_path, config_path, cache_path, data_path, failedWriteAccess);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// create default MLC files or quit if it fails
|
||||||
|
void CemuApp::InitializeNewMLCOrFail(fs::path mlc)
|
||||||
|
{
|
||||||
|
if( CemuApp::CreateDefaultMLCFiles(mlc) )
|
||||||
|
return; // all good
|
||||||
|
cemu_assert_debug(!ActiveSettings::IsCustomMlcPath()); // should not be possible?
|
||||||
|
|
||||||
|
if(ActiveSettings::IsCommandLineMlcPath() || ActiveSettings::IsCustomMlcPath())
|
||||||
|
{
|
||||||
|
// tell user that the custom path is not writable
|
||||||
|
wxMessageBox(formatWxString(_("Cemu failed to write to the custom mlc directory.\nThe path is:\n{}"), wxHelper::FromPath(mlc)), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
wxMessageBox(formatWxString(_("Cemu failed to write to the mlc directory.\nThe path is:\n{}"), wxHelper::FromPath(mlc)), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemuApp::InitializeExistingMLCOrFail(fs::path mlc)
|
||||||
|
{
|
||||||
|
if(CreateDefaultMLCFiles(mlc))
|
||||||
|
return; // all good
|
||||||
|
// failed to write mlc files
|
||||||
|
if(ActiveSettings::IsCommandLineMlcPath() || ActiveSettings::IsCustomMlcPath())
|
||||||
|
{
|
||||||
|
// tell user that the custom path is not writable
|
||||||
|
// if it's a command line path then just quit. Otherwise ask if user wants to reset the path
|
||||||
|
if(ActiveSettings::IsCommandLineMlcPath())
|
||||||
|
{
|
||||||
|
wxMessageBox(formatWxString(_("Cemu failed to write to the custom mlc directory.\nThe path is:\n{}"), wxHelper::FromPath(mlc)), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
// ask user if they want to reset the path
|
||||||
|
const wxString message = formatWxString(_("Cemu failed to write to the custom mlc directory.\n\nThe path is:\n{}\n\nCemu cannot start without a valid mlc path. Do you want to reset the path? You can later change it again in the General Settings."),
|
||||||
|
_pathToUtf8(mlc));
|
||||||
|
wxMessageDialog dialog(nullptr, message, _("Error"), wxCENTRE | wxYES_NO | wxICON_WARNING);
|
||||||
|
dialog.SetYesNoLabels(_("Reset path"), _("Exit"));
|
||||||
|
const auto dialogResult = dialog.ShowModal();
|
||||||
|
if (dialogResult == wxID_NO)
|
||||||
|
exit(0);
|
||||||
|
else // reset path
|
||||||
|
{
|
||||||
|
GetConfig().mlc_path = "";
|
||||||
|
g_config.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CemuApp::OnInit()
|
||||||
|
{
|
||||||
|
std::set<fs::path> failedWriteAccess;
|
||||||
|
DeterminePaths(failedWriteAccess);
|
||||||
|
// make sure default cemu directories exist
|
||||||
|
CreateDefaultCemuFiles();
|
||||||
|
|
||||||
|
g_config.SetFilename(ActiveSettings::GetConfigPath("settings.xml").generic_wstring());
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
bool isFirstStart = !fs::exists(ActiveSettings::GetConfigPath("settings.xml"), ec);
|
||||||
|
|
||||||
NetworkConfig::LoadOnce();
|
NetworkConfig::LoadOnce();
|
||||||
|
if(!isFirstStart)
|
||||||
|
{
|
||||||
g_config.Load();
|
g_config.Load();
|
||||||
|
LocalizeUI(static_cast<wxLanguage>(GetConfig().language == wxLANGUAGE_DEFAULT ? wxLocale::GetSystemLanguage() : GetConfig().language.GetValue()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LocalizeUI(static_cast<wxLanguage>(wxLocale::GetSystemLanguage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto&& path : failedWriteAccess)
|
||||||
|
{
|
||||||
|
wxMessageBox(formatWxString(_("Cemu can't write to {}!"), wxString::FromUTF8(_pathToUtf8(path))),
|
||||||
|
_("Warning"), wxOK | wxCENTRE | wxICON_EXCLAMATION, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFirstStart)
|
||||||
|
{
|
||||||
|
// show the getting started dialog
|
||||||
|
GettingStartedDialog dia(nullptr);
|
||||||
|
dia.ShowModal();
|
||||||
|
// make sure config is created. Gfx pack UI and input UI may create it earlier already, but we still want to update it
|
||||||
|
g_config.Save();
|
||||||
|
// create mlc, on failure the user can quit here. So do this after the Getting Started dialog
|
||||||
|
InitializeNewMLCOrFail(ActiveSettings::GetMlcPath());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check if mlc is valid and recreate default files
|
||||||
|
InitializeExistingMLCOrFail(ActiveSettings::GetMlcPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActiveSettings::Init(); // this is a bit of a misnomer, right now this call only loads certs for online play. In the future we should move the logic to a more appropriate place
|
||||||
HandlePostUpdate();
|
HandlePostUpdate();
|
||||||
mainEmulatorHLE();
|
|
||||||
|
LatteOverlay_init();
|
||||||
|
// run a couple of tests if in non-release mode
|
||||||
|
#ifdef CEMU_DEBUG_ASSERT
|
||||||
|
UnitTests();
|
||||||
|
#endif
|
||||||
|
CemuCommonInit();
|
||||||
|
|
||||||
wxInitAllImageHandlers();
|
wxInitAllImageHandlers();
|
||||||
|
|
||||||
LocalizeUI();
|
|
||||||
|
|
||||||
// fill colour db
|
// fill colour db
|
||||||
wxTheColourDatabase->AddColour("ERROR", wxColour(0xCC, 0, 0));
|
wxTheColourDatabase->AddColour("ERROR", wxColour(0xCC, 0, 0));
|
||||||
wxTheColourDatabase->AddColour("SUCCESS", wxColour(0, 0xbb, 0));
|
wxTheColourDatabase->AddColour("SUCCESS", wxColour(0, 0xbb, 0));
|
||||||
@ -135,15 +308,8 @@ bool CemuApp::OnInit()
|
|||||||
Bind(wxEVT_ACTIVATE_APP, &CemuApp::ActivateApp, this);
|
Bind(wxEVT_ACTIVATE_APP, &CemuApp::ActivateApp, this);
|
||||||
|
|
||||||
auto& config = GetConfig();
|
auto& config = GetConfig();
|
||||||
const bool first_start = !config.did_show_graphic_pack_download;
|
|
||||||
|
|
||||||
CreateDefaultFiles(first_start);
|
|
||||||
|
|
||||||
m_mainFrame = new MainWindow();
|
m_mainFrame = new MainWindow();
|
||||||
|
|
||||||
if (first_start)
|
|
||||||
m_mainFrame->ShowGettingStartedDialog();
|
|
||||||
|
|
||||||
std::unique_lock lock(g_mutex);
|
std::unique_lock lock(g_mutex);
|
||||||
g_window_info.app_active = true;
|
g_window_info.app_active = true;
|
||||||
|
|
||||||
@ -230,22 +396,22 @@ std::vector<const wxLanguageInfo *> CemuApp::GetLanguages() const {
|
|||||||
return availableLanguages;
|
return availableLanguages;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CemuApp::LocalizeUI()
|
void CemuApp::LocalizeUI(wxLanguage languageToUse)
|
||||||
{
|
{
|
||||||
std::unique_ptr<wxTranslations> translationsMgr(new wxTranslations());
|
std::unique_ptr<wxTranslations> translationsMgr(new wxTranslations());
|
||||||
m_availableTranslations = GetAvailableTranslationLanguages(translationsMgr.get());
|
m_availableTranslations = GetAvailableTranslationLanguages(translationsMgr.get());
|
||||||
|
|
||||||
const sint32 configuredLanguage = GetConfig().language;
|
|
||||||
bool isTranslationAvailable = std::any_of(m_availableTranslations.begin(), m_availableTranslations.end(),
|
bool isTranslationAvailable = std::any_of(m_availableTranslations.begin(), m_availableTranslations.end(),
|
||||||
[configuredLanguage](const wxLanguageInfo* info) { return info->Language == configuredLanguage; });
|
[languageToUse](const wxLanguageInfo* info) { return info->Language == languageToUse; });
|
||||||
if (configuredLanguage == wxLANGUAGE_DEFAULT || isTranslationAvailable)
|
if (languageToUse == wxLANGUAGE_DEFAULT || isTranslationAvailable)
|
||||||
{
|
{
|
||||||
translationsMgr->SetLanguage(static_cast<wxLanguage>(configuredLanguage));
|
translationsMgr->SetLanguage(static_cast<wxLanguage>(languageToUse));
|
||||||
translationsMgr->AddCatalog("cemu");
|
translationsMgr->AddCatalog("cemu");
|
||||||
|
|
||||||
if (translationsMgr->IsLoaded("cemu") && wxLocale::IsAvailable(configuredLanguage))
|
if (translationsMgr->IsLoaded("cemu") && wxLocale::IsAvailable(languageToUse))
|
||||||
m_locale.Init(configuredLanguage);
|
{
|
||||||
|
m_locale.Init(languageToUse);
|
||||||
|
}
|
||||||
// This must be run after wxLocale::Init, as the latter sets up its own wxTranslations instance which we want to override
|
// This must be run after wxLocale::Init, as the latter sets up its own wxTranslations instance which we want to override
|
||||||
wxTranslations::Set(translationsMgr.release());
|
wxTranslations::Set(translationsMgr.release());
|
||||||
}
|
}
|
||||||
@ -264,55 +430,47 @@ std::vector<const wxLanguageInfo*> CemuApp::GetAvailableTranslationLanguages(wxT
|
|||||||
return languages;
|
return languages;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CemuApp::CreateDefaultFiles(bool first_start)
|
bool CemuApp::CheckMLCPath(const fs::path& mlc)
|
||||||
{
|
{
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
fs::path mlc = ActiveSettings::GetMlcPath();
|
if (!fs::exists(mlc, ec))
|
||||||
// check for mlc01 folder missing if custom path has been set
|
return false;
|
||||||
if (!fs::exists(mlc, ec) && !first_start)
|
if (!fs::exists(mlc / "usr", ec) || !fs::exists(mlc / "sys", ec))
|
||||||
{
|
return false;
|
||||||
const wxString message = formatWxString(_("Your mlc01 folder seems to be missing.\n\nThis is where Cemu stores save files, game updates and other Wii U files.\n\nThe expected path is:\n{}\n\nDo you want to create the folder at the expected path?"),
|
return true;
|
||||||
_pathToUtf8(mlc));
|
}
|
||||||
|
|
||||||
wxMessageDialog dialog(nullptr, message, _("Error"), wxCENTRE | wxYES_NO | wxCANCEL| wxICON_WARNING);
|
bool CemuApp::CreateDefaultMLCFiles(const fs::path& mlc)
|
||||||
dialog.SetYesNoCancelLabels(_("Yes"), _("No"), _("Select a custom path"));
|
{
|
||||||
const auto dialogResult = dialog.ShowModal();
|
auto CreateDirectoriesIfNotExist = [](const fs::path& path)
|
||||||
if (dialogResult == wxID_NO)
|
|
||||||
exit(0);
|
|
||||||
else if(dialogResult == wxID_CANCEL)
|
|
||||||
{
|
{
|
||||||
if (!SelectMLCPath())
|
std::error_code ec;
|
||||||
return;
|
if (!fs::exists(path, ec))
|
||||||
mlc = ActiveSettings::GetMlcPath();
|
return fs::create_directories(path, ec);
|
||||||
}
|
return true;
|
||||||
else
|
};
|
||||||
|
// list of directories to create
|
||||||
|
const fs::path directories[] = {
|
||||||
|
mlc,
|
||||||
|
mlc / "sys",
|
||||||
|
mlc / "usr",
|
||||||
|
mlc / "usr/title/00050000", // base
|
||||||
|
mlc / "usr/title/0005000c", // dlc
|
||||||
|
mlc / "usr/title/0005000e", // update
|
||||||
|
mlc / "usr/save/00050010/1004a000/user/common/db", // Mii Maker save folders {0x500101004A000, 0x500101004A100, 0x500101004A200}
|
||||||
|
mlc / "usr/save/00050010/1004a100/user/common/db",
|
||||||
|
mlc / "usr/save/00050010/1004a200/user/common/db",
|
||||||
|
mlc / "sys/title/0005001b/1005c000/content" // lang files
|
||||||
|
};
|
||||||
|
for(auto& path : directories)
|
||||||
{
|
{
|
||||||
GetConfig().mlc_path = "";
|
if(!CreateDirectoriesIfNotExist(path))
|
||||||
g_config.Save();
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// create sys/usr folder in mlc01
|
// create sys/usr folder in mlc01
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const auto sysFolder = fs::path(mlc).append("sys");
|
|
||||||
fs::create_directories(sysFolder);
|
|
||||||
|
|
||||||
const auto usrFolder = fs::path(mlc).append("usr");
|
|
||||||
fs::create_directories(usrFolder);
|
|
||||||
fs::create_directories(fs::path(usrFolder).append("title/00050000")); // base
|
|
||||||
fs::create_directories(fs::path(usrFolder).append("title/0005000c")); // dlc
|
|
||||||
fs::create_directories(fs::path(usrFolder).append("title/0005000e")); // update
|
|
||||||
|
|
||||||
// Mii Maker save folders {0x500101004A000, 0x500101004A100, 0x500101004A200},
|
|
||||||
fs::create_directories(fs::path(mlc).append("usr/save/00050010/1004a000/user/common/db"));
|
|
||||||
fs::create_directories(fs::path(mlc).append("usr/save/00050010/1004a100/user/common/db"));
|
|
||||||
fs::create_directories(fs::path(mlc).append("usr/save/00050010/1004a200/user/common/db"));
|
|
||||||
|
|
||||||
// lang files
|
|
||||||
const auto langDir = fs::path(mlc).append("sys/title/0005001b/1005c000/content");
|
const auto langDir = fs::path(mlc).append("sys/title/0005001b/1005c000/content");
|
||||||
fs::create_directories(langDir);
|
|
||||||
|
|
||||||
auto langFile = fs::path(langDir).append("language.txt");
|
auto langFile = fs::path(langDir).append("language.txt");
|
||||||
if (!fs::exists(langFile))
|
if (!fs::exists(langFile))
|
||||||
{
|
{
|
||||||
@ -346,18 +504,13 @@ void CemuApp::CreateDefaultFiles(bool first_start)
|
|||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
{
|
{
|
||||||
wxString errorMsg = formatWxString(_("Couldn't create a required mlc01 subfolder or file!\n\nError: {0}\nTarget path:\n{1}"), ex.what(), _pathToUtf8(mlc));
|
return false;
|
||||||
|
|
||||||
#if BOOST_OS_WINDOWS
|
|
||||||
const DWORD lastError = GetLastError();
|
|
||||||
if (lastError != ERROR_SUCCESS)
|
|
||||||
errorMsg << fmt::format("\n\n{}", GetSystemErrorMessage(lastError));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wxMessageBox(errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemuApp::CreateDefaultCemuFiles()
|
||||||
|
{
|
||||||
// cemu directories
|
// cemu directories
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -384,58 +537,6 @@ void CemuApp::CreateDefaultFiles(bool first_start)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CemuApp::TrySelectMLCPath(fs::path path)
|
|
||||||
{
|
|
||||||
if (path.empty())
|
|
||||||
path = ActiveSettings::GetDefaultMLCPath();
|
|
||||||
|
|
||||||
if (!TestWriteAccess(path))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
GetConfig().SetMLCPath(path);
|
|
||||||
CemuApp::CreateDefaultFiles();
|
|
||||||
|
|
||||||
// update TitleList and SaveList scanner with new MLC path
|
|
||||||
CafeTitleList::SetMLCPath(path);
|
|
||||||
CafeTitleList::Refresh();
|
|
||||||
CafeSaveList::SetMLCPath(path);
|
|
||||||
CafeSaveList::Refresh();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CemuApp::SelectMLCPath(wxWindow* parent)
|
|
||||||
{
|
|
||||||
auto& config = GetConfig();
|
|
||||||
|
|
||||||
fs::path default_path;
|
|
||||||
if (fs::exists(_utf8ToPath(config.mlc_path.GetValue())))
|
|
||||||
default_path = _utf8ToPath(config.mlc_path.GetValue());
|
|
||||||
|
|
||||||
// try until users selects a valid path or aborts
|
|
||||||
while(true)
|
|
||||||
{
|
|
||||||
wxDirDialog path_dialog(parent, _("Select a mlc directory"), wxHelper::FromPath(default_path), wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
|
|
||||||
if (path_dialog.ShowModal() != wxID_OK || path_dialog.GetPath().empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto path = path_dialog.GetPath().ToStdWstring();
|
|
||||||
|
|
||||||
if (!TrySelectMLCPath(path))
|
|
||||||
{
|
|
||||||
const auto result = wxMessageBox(_("Cemu can't write to the selected mlc path!\nDo you want to select another path?"), _("Error"), wxYES_NO | wxCENTRE | wxICON_ERROR);
|
|
||||||
if (result == wxYES)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CemuApp::ActivateApp(wxActivateEvent& event)
|
void CemuApp::ActivateApp(wxActivateEvent& event)
|
||||||
{
|
{
|
||||||
g_window_info.app_active = event.GetActive();
|
g_window_info.app_active = event.GetActive();
|
||||||
|
@ -15,13 +15,18 @@ public:
|
|||||||
|
|
||||||
std::vector<const wxLanguageInfo*> GetLanguages() const;
|
std::vector<const wxLanguageInfo*> GetLanguages() const;
|
||||||
|
|
||||||
static void CreateDefaultFiles(bool first_start = false);
|
static bool CheckMLCPath(const fs::path& mlc);
|
||||||
static bool TrySelectMLCPath(fs::path path);
|
static bool CreateDefaultMLCFiles(const fs::path& mlc);
|
||||||
static bool SelectMLCPath(wxWindow* parent = nullptr);
|
static void CreateDefaultCemuFiles();
|
||||||
|
|
||||||
|
static void InitializeNewMLCOrFail(fs::path mlc);
|
||||||
|
static void InitializeExistingMLCOrFail(fs::path mlc);
|
||||||
private:
|
private:
|
||||||
|
void LocalizeUI(wxLanguage languageToUse);
|
||||||
|
|
||||||
|
void DeterminePaths(std::set<fs::path>& failedWriteAccess);
|
||||||
|
|
||||||
void ActivateApp(wxActivateEvent& event);
|
void ActivateApp(wxActivateEvent& event);
|
||||||
void LocalizeUI();
|
|
||||||
static std::vector<const wxLanguageInfo*> GetAvailableTranslationLanguages(wxTranslations* translationsMgr);
|
static std::vector<const wxLanguageInfo*> GetAvailableTranslationLanguages(wxTranslations* translationsMgr);
|
||||||
|
|
||||||
MainWindow* m_mainFrame = nullptr;
|
MainWindow* m_mainFrame = nullptr;
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
#include <boost/tokenizer.hpp>
|
#include <boost/tokenizer.hpp>
|
||||||
#include "util/helpers/SystemException.h"
|
#include "util/helpers/SystemException.h"
|
||||||
#include "gui/dialogs/CreateAccount/wxCreateAccountDialog.h"
|
#include "gui/dialogs/CreateAccount/wxCreateAccountDialog.h"
|
||||||
#include "config/PermanentStorage.h"
|
|
||||||
|
|
||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
#include <VersionHelpers.h>
|
#include <VersionHelpers.h>
|
||||||
@ -176,10 +175,6 @@ wxPanel* GeneralSettings2::AddGeneralPage(wxNotebook* notebook)
|
|||||||
m_save_screenshot->SetToolTip(_("Pressing the screenshot key (F12) will save a screenshot directly to the screenshots folder"));
|
m_save_screenshot->SetToolTip(_("Pressing the screenshot key (F12) will save a screenshot directly to the screenshots folder"));
|
||||||
second_row->Add(m_save_screenshot, 0, botflag, 5);
|
second_row->Add(m_save_screenshot, 0, botflag, 5);
|
||||||
|
|
||||||
m_permanent_storage = new wxCheckBox(box, wxID_ANY, _("Use permanent storage"));
|
|
||||||
m_permanent_storage->SetToolTip(_("Cemu will remember your custom mlc path in %LOCALAPPDATA%/Cemu for new installations."));
|
|
||||||
second_row->Add(m_permanent_storage, 0, botflag, 5);
|
|
||||||
second_row->AddSpacer(10);
|
|
||||||
m_disable_screensaver = new wxCheckBox(box, wxID_ANY, _("Disable screen saver"));
|
m_disable_screensaver = new wxCheckBox(box, wxID_ANY, _("Disable screen saver"));
|
||||||
m_disable_screensaver->SetToolTip(_("Prevents the system from activating the screen saver or going to sleep while running a game."));
|
m_disable_screensaver->SetToolTip(_("Prevents the system from activating the screen saver or going to sleep while running a game."));
|
||||||
second_row->Add(m_disable_screensaver, 0, botflag, 5);
|
second_row->Add(m_disable_screensaver, 0, botflag, 5);
|
||||||
@ -203,23 +198,33 @@ wxPanel* GeneralSettings2::AddGeneralPage(wxNotebook* notebook)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto* box = new wxStaticBox(panel, wxID_ANY, _("MLC Path"));
|
auto* outerMlcBox = new wxStaticBox(panel, wxID_ANY, _("Custom MLC path"));
|
||||||
auto* box_sizer = new wxStaticBoxSizer(box, wxHORIZONTAL);
|
|
||||||
|
|
||||||
m_mlc_path = new wxTextCtrl(box, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY);
|
auto* box_sizer_mlc = new wxStaticBoxSizer(outerMlcBox, wxVERTICAL);
|
||||||
|
box_sizer_mlc->Add(new wxStaticText(box_sizer_mlc->GetStaticBox(), wxID_ANY, _("You can configure a custom path for the emulated internal Wii U storage (MLC).\nThis is where Cemu stores saves, accounts and other Wii U system files."), wxDefaultPosition, wxDefaultSize, 0), 0, wxALL, 5);
|
||||||
|
|
||||||
|
auto* mlcPathLineSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
|
m_mlc_path = new wxTextCtrl(outerMlcBox, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY);
|
||||||
m_mlc_path->SetMinSize(wxSize(150, -1));
|
m_mlc_path->SetMinSize(wxSize(150, -1));
|
||||||
m_mlc_path->Bind(wxEVT_CHAR, &GeneralSettings2::OnMLCPathChar, this);
|
|
||||||
m_mlc_path->SetToolTip(_("The mlc directory contains your save games and installed game update/dlc data"));
|
m_mlc_path->SetToolTip(_("The mlc directory contains your save games and installed game update/dlc data"));
|
||||||
|
|
||||||
box_sizer->Add(m_mlc_path, 1, wxALL | wxEXPAND, 5);
|
mlcPathLineSizer->Add(m_mlc_path, 1, wxALL | wxEXPAND, 5);
|
||||||
|
|
||||||
auto* change_path = new wxButton(box, wxID_ANY, "...");
|
auto* changePath = new wxButton(outerMlcBox, wxID_ANY, "Change");
|
||||||
change_path->Bind(wxEVT_BUTTON, &GeneralSettings2::OnMLCPathSelect, this);
|
changePath->Bind(wxEVT_BUTTON, &GeneralSettings2::OnMLCPathSelect, this);
|
||||||
change_path->SetToolTip(_("Select a custom mlc path\nThe mlc path is used to store Wii U related files like save games, game updates and dlc data"));
|
mlcPathLineSizer->Add(changePath, 0, wxALL, 5);
|
||||||
box_sizer->Add(change_path, 0, wxALL, 5);
|
|
||||||
if (LaunchSettings::GetMLCPath().has_value())
|
if (LaunchSettings::GetMLCPath().has_value())
|
||||||
change_path->Disable();
|
changePath->Disable();
|
||||||
general_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);
|
|
||||||
|
auto* clearPath = new wxButton(outerMlcBox, wxID_ANY, "Clear custom path");
|
||||||
|
clearPath->Bind(wxEVT_BUTTON, &GeneralSettings2::OnMLCPathClear, this);
|
||||||
|
mlcPathLineSizer->Add(clearPath, 0, wxALL, 5);
|
||||||
|
if (LaunchSettings::GetMLCPath().has_value() || !ActiveSettings::IsCustomMlcPath())
|
||||||
|
clearPath->Disable();
|
||||||
|
|
||||||
|
box_sizer_mlc->Add(mlcPathLineSizer, 0, wxEXPAND, 5);
|
||||||
|
general_panel_sizer->Add(box_sizer_mlc, 0, wxEXPAND | wxALL, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -897,30 +902,6 @@ void GeneralSettings2::StoreConfig()
|
|||||||
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
||||||
config.feral_gamemode = m_feral_gamemode->IsChecked();
|
config.feral_gamemode = m_feral_gamemode->IsChecked();
|
||||||
#endif
|
#endif
|
||||||
const bool use_ps = m_permanent_storage->IsChecked();
|
|
||||||
if(use_ps)
|
|
||||||
{
|
|
||||||
config.permanent_storage = use_ps;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
PermanentStorage storage;
|
|
||||||
storage.RemoveStorage();
|
|
||||||
}
|
|
||||||
catch (...) {}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// delete permanent storage
|
|
||||||
PermanentStorage storage;
|
|
||||||
storage.RemoveStorage();
|
|
||||||
}
|
|
||||||
catch (...) {}
|
|
||||||
config.permanent_storage = use_ps;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.disable_screensaver = m_disable_screensaver->IsChecked();
|
config.disable_screensaver = m_disable_screensaver->IsChecked();
|
||||||
// Toggle while a game is running
|
// Toggle while a game is running
|
||||||
if (CafeSystem::IsTitleRunning())
|
if (CafeSystem::IsTitleRunning())
|
||||||
@ -928,9 +909,6 @@ void GeneralSettings2::StoreConfig()
|
|||||||
ScreenSaver::SetInhibit(config.disable_screensaver);
|
ScreenSaver::SetInhibit(config.disable_screensaver);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!LaunchSettings::GetMLCPath().has_value())
|
|
||||||
config.SetMLCPath(wxHelper::MakeFSPath(m_mlc_path->GetValue()), false);
|
|
||||||
|
|
||||||
// -1 is default wx widget value -> set to dummy 0 so mainwindow and padwindow will update it
|
// -1 is default wx widget value -> set to dummy 0 so mainwindow and padwindow will update it
|
||||||
config.window_position = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
|
config.window_position = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
|
||||||
config.window_size = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
|
config.window_size = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
|
||||||
@ -1560,7 +1538,6 @@ void GeneralSettings2::ApplyConfig()
|
|||||||
m_auto_update->SetValue(config.check_update);
|
m_auto_update->SetValue(config.check_update);
|
||||||
m_save_screenshot->SetValue(config.save_screenshot);
|
m_save_screenshot->SetValue(config.save_screenshot);
|
||||||
|
|
||||||
m_permanent_storage->SetValue(config.permanent_storage);
|
|
||||||
m_disable_screensaver->SetValue(config.disable_screensaver);
|
m_disable_screensaver->SetValue(config.disable_screensaver);
|
||||||
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
||||||
m_feral_gamemode->SetValue(config.feral_gamemode);
|
m_feral_gamemode->SetValue(config.feral_gamemode);
|
||||||
@ -1570,6 +1547,7 @@ void GeneralSettings2::ApplyConfig()
|
|||||||
m_disable_screensaver->SetValue(false);
|
m_disable_screensaver->SetValue(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
m_game_paths->Clear();
|
||||||
for (auto& path : config.game_paths)
|
for (auto& path : config.game_paths)
|
||||||
{
|
{
|
||||||
m_game_paths->Append(to_wxString(path));
|
m_game_paths->Append(to_wxString(path));
|
||||||
@ -1985,34 +1963,70 @@ void GeneralSettings2::OnAccountServiceChanged(wxCommandEvent& event)
|
|||||||
|
|
||||||
void GeneralSettings2::OnMLCPathSelect(wxCommandEvent& event)
|
void GeneralSettings2::OnMLCPathSelect(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
if (!CemuApp::SelectMLCPath(this))
|
if(CafeSystem::IsTitleRunning())
|
||||||
|
{
|
||||||
|
wxMessageBox(_("Can't change MLC path while a game is running!"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
m_mlc_path->SetValue(wxHelper::FromPath(ActiveSettings::GetMlcPath()));
|
// show directory dialog
|
||||||
m_reload_gamelist = true;
|
wxDirDialog path_dialog(this, _("Select MLC directory"), wxEmptyString, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
|
||||||
m_mlc_modified = true;
|
if (path_dialog.ShowModal() != wxID_OK || path_dialog.GetPath().empty())
|
||||||
|
return;
|
||||||
|
// check if the choosen MLC path is an already initialized MLC location
|
||||||
|
fs::path newMlc = wxHelper::MakeFSPath(path_dialog.GetPath());
|
||||||
|
if(CemuApp::CheckMLCPath(newMlc))
|
||||||
|
{
|
||||||
|
// ask user if they are sure they want to use this folder and let them know that accounts and saves wont transfer
|
||||||
|
wxString message = _("Note that changing the MLC location will not transfer any accounts or save files. Are you sure you want to change the path?");
|
||||||
|
wxMessageDialog dialog(this, message, _("Warning"), wxYES_NO | wxCENTRE | wxICON_WARNING);
|
||||||
|
if(dialog.ShowModal() == wxID_NO)
|
||||||
|
return;
|
||||||
|
if( !CemuApp::CreateDefaultMLCFiles(newMlc) ) // creating also acts as a check for read+write access
|
||||||
|
{
|
||||||
|
wxMessageBox(_("Failed to create default MLC files in the selected directory. The MLC path has not been changed"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ask user if they want to create a new mlc structure at the choosen location
|
||||||
|
wxString message = _("The selected directory does not contain the expected MLC structure. Do you want to create a new MLC structure in this directory?\nNote that changing the MLC location will not transfer any accounts or save files.");
|
||||||
|
wxMessageDialog dialog(this, message, _("Warning"), wxYES_NO | wxCENTRE | wxICON_WARNING);
|
||||||
|
if( !CemuApp::CreateDefaultMLCFiles(newMlc) )
|
||||||
|
{
|
||||||
|
wxMessageBox(_("Failed to create default MLC files in the selected directory. The MLC path has not been changed"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update MLC path and store any other modified settings
|
||||||
|
GetConfig().SetMLCPath(newMlc);
|
||||||
|
StoreConfig();
|
||||||
|
wxMessageBox(_("Cemu needs to be restarted for the changes to take effect."), _("Information"), wxOK | wxCENTRE | wxICON_INFORMATION, this);
|
||||||
|
// close settings and then cemu
|
||||||
|
wxCloseEvent closeEvent(wxEVT_CLOSE_WINDOW);
|
||||||
|
wxPostEvent(this, closeEvent);
|
||||||
|
wxPostEvent(GetParent(), closeEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneralSettings2::OnMLCPathChar(wxKeyEvent& event)
|
void GeneralSettings2::OnMLCPathClear(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
if (LaunchSettings::GetMLCPath().has_value())
|
if(CafeSystem::IsTitleRunning())
|
||||||
return;
|
|
||||||
|
|
||||||
if(event.GetKeyCode() == WXK_DELETE || event.GetKeyCode() == WXK_BACK)
|
|
||||||
{
|
{
|
||||||
fs::path newPath = "";
|
wxMessageBox(_("Can't change MLC path while a game is running!"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this);
|
||||||
if(!CemuApp::TrySelectMLCPath(newPath))
|
|
||||||
{
|
|
||||||
const auto res = wxMessageBox(_("The default MLC path is inaccessible.\nDo you want to select a different path?"), _("Error"), wxYES_NO | wxCENTRE | wxICON_ERROR);
|
|
||||||
if (res == wxYES && CemuApp::SelectMLCPath(this))
|
|
||||||
newPath = ActiveSettings::GetMlcPath();
|
|
||||||
else
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_mlc_path->SetValue(wxHelper::FromPath(newPath));
|
wxString message = _("Note that changing the MLC location will not transfer any accounts or save files. Are you sure you want to change the path?");
|
||||||
m_reload_gamelist = true;
|
wxMessageDialog dialog(this, message, _("Warning"), wxYES_NO | wxCENTRE | wxICON_WARNING);
|
||||||
m_mlc_modified = true;
|
if(dialog.ShowModal() == wxID_NO)
|
||||||
}
|
return;
|
||||||
|
GetConfig().SetMLCPath("");
|
||||||
|
StoreConfig();
|
||||||
|
g_config.Save();
|
||||||
|
wxMessageBox(_("Cemu needs to be restarted for the changes to take effect."), _("Information"), wxOK | wxCENTRE | wxICON_INFORMATION, this);
|
||||||
|
// close settings and then cemu
|
||||||
|
wxCloseEvent closeEvent(wxEVT_CLOSE_WINDOW);
|
||||||
|
wxPostEvent(this, closeEvent);
|
||||||
|
wxPostEvent(GetParent(), closeEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneralSettings2::OnShowOnlineValidator(wxCommandEvent& event)
|
void GeneralSettings2::OnShowOnlineValidator(wxCommandEvent& event)
|
||||||
|
@ -42,7 +42,6 @@ private:
|
|||||||
wxCheckBox* m_save_padwindow_position_size;
|
wxCheckBox* m_save_padwindow_position_size;
|
||||||
wxCheckBox* m_discord_presence, *m_fullscreen_menubar;
|
wxCheckBox* m_discord_presence, *m_fullscreen_menubar;
|
||||||
wxCheckBox* m_auto_update, *m_save_screenshot;
|
wxCheckBox* m_auto_update, *m_save_screenshot;
|
||||||
wxCheckBox* m_permanent_storage;
|
|
||||||
wxCheckBox* m_disable_screensaver;
|
wxCheckBox* m_disable_screensaver;
|
||||||
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
||||||
wxCheckBox* m_feral_gamemode;
|
wxCheckBox* m_feral_gamemode;
|
||||||
@ -96,7 +95,7 @@ private:
|
|||||||
void OnRemovePathClicked(wxCommandEvent& event);
|
void OnRemovePathClicked(wxCommandEvent& event);
|
||||||
void OnActiveAccountChanged(wxCommandEvent& event);
|
void OnActiveAccountChanged(wxCommandEvent& event);
|
||||||
void OnMLCPathSelect(wxCommandEvent& event);
|
void OnMLCPathSelect(wxCommandEvent& event);
|
||||||
void OnMLCPathChar(wxKeyEvent& event);
|
void OnMLCPathClear(wxCommandEvent& event);
|
||||||
void OnShowOnlineValidator(wxCommandEvent& event);
|
void OnShowOnlineValidator(wxCommandEvent& event);
|
||||||
void OnAccountServiceChanged(wxCommandEvent& event);
|
void OnAccountServiceChanged(wxCommandEvent& event);
|
||||||
static wxString GetOnlineAccountErrorMessage(OnlineAccountError error);
|
static wxString GetOnlineAccountErrorMessage(OnlineAccountError error);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <wx/filepicker.h>
|
#include <wx/filepicker.h>
|
||||||
#include <wx/statbox.h>
|
#include <wx/statbox.h>
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
|
#include <wx/radiobox.h>
|
||||||
|
|
||||||
#include "config/ActiveSettings.h"
|
#include "config/ActiveSettings.h"
|
||||||
#include "gui/CemuApp.h"
|
#include "gui/CemuApp.h"
|
||||||
@ -11,7 +12,6 @@
|
|||||||
#include "gui/GraphicPacksWindow2.h"
|
#include "gui/GraphicPacksWindow2.h"
|
||||||
#include "gui/input/InputSettings2.h"
|
#include "gui/input/InputSettings2.h"
|
||||||
#include "config/CemuConfig.h"
|
#include "config/CemuConfig.h"
|
||||||
#include "config/PermanentConfig.h"
|
|
||||||
|
|
||||||
#include "Cafe/TitleList/TitleList.h"
|
#include "Cafe/TitleList/TitleList.h"
|
||||||
|
|
||||||
@ -21,75 +21,100 @@
|
|||||||
|
|
||||||
#include "wxHelper.h"
|
#include "wxHelper.h"
|
||||||
|
|
||||||
|
wxDEFINE_EVENT(EVT_REFRESH_FIRST_PAGE, wxCommandEvent); // used to refresh the first page after the language change
|
||||||
|
|
||||||
wxPanel* GettingStartedDialog::CreatePage1()
|
wxPanel* GettingStartedDialog::CreatePage1()
|
||||||
{
|
{
|
||||||
auto* result = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
auto* mainPanel = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||||
auto* page1_sizer = new wxBoxSizer(wxVERTICAL);
|
auto* page1_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
{
|
{
|
||||||
auto* sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto* sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
sizer->Add(new wxStaticBitmap(mainPanel, wxID_ANY, wxICON(M_WND_ICON128)), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||||
sizer->Add(new wxStaticBitmap(result, wxID_ANY, wxICON(M_WND_ICON128)), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
m_page1.staticText11 = new wxStaticText(mainPanel, wxID_ANY, _("It looks like you're starting Cemu for the first time.\nThis quick setup assistant will help you get the best experience"), wxDefaultPosition, wxDefaultSize, 0);
|
||||||
|
m_page1.staticText11->Wrap(-1);
|
||||||
auto* m_staticText11 = new wxStaticText(result, wxID_ANY, _("It looks like you're starting Cemu for the first time.\nThis quick setup assistant will help you get the best experience"), wxDefaultPosition, wxDefaultSize, 0);
|
sizer->Add(m_page1.staticText11, 0, wxALL, 5);
|
||||||
m_staticText11->Wrap(-1);
|
|
||||||
sizer->Add(m_staticText11, 0, wxALL, 5);
|
|
||||||
|
|
||||||
page1_sizer->Add(sizer, 0, wxALL | wxEXPAND, 5);
|
page1_sizer->Add(sizer, 0, wxALL | wxEXPAND, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ActiveSettings::IsPortableMode())
|
||||||
{
|
{
|
||||||
m_mlc_box_sizer = new wxStaticBoxSizer(wxVERTICAL, result, _("mlc01 path"));
|
m_page1.portableModeInfoText = new wxStaticText(mainPanel, wxID_ANY, _("Cemu is running in portable mode"));
|
||||||
m_mlc_box_sizer->Add(new wxStaticText(m_mlc_box_sizer->GetStaticBox(), wxID_ANY, _("The mlc path is the root folder of the emulated Wii U internal flash storage. It contains all your saves, installed updates and DLCs.\nIt is strongly recommend that you create a dedicated folder for it (example: C:\\wiiu\\mlc\\) \nIf left empty, the mlc folder will be created inside the Cemu folder.")), 0, wxALL, 5);
|
m_page1.portableModeInfoText->Show(true);
|
||||||
|
page1_sizer->Add(m_page1.portableModeInfoText, 0, wxALL, 5);
|
||||||
|
|
||||||
m_prev_mlc_warning = new wxStaticText(m_mlc_box_sizer->GetStaticBox(), wxID_ANY, _("A custom mlc path from a previous Cemu installation has been found and filled in."));
|
|
||||||
m_prev_mlc_warning->SetForegroundColour(*wxRED);
|
|
||||||
m_prev_mlc_warning->Show(false);
|
|
||||||
m_mlc_box_sizer->Add(m_prev_mlc_warning, 0, wxALL, 5);
|
|
||||||
|
|
||||||
auto* mlc_path_sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
mlc_path_sizer->Add(new wxStaticText(m_mlc_box_sizer->GetStaticBox(), wxID_ANY, _("Custom mlc01 path")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
|
||||||
|
|
||||||
// workaround since we can't specify our own browse label? >> _("Browse")
|
|
||||||
m_mlc_folder = new wxDirPickerCtrl(m_mlc_box_sizer->GetStaticBox(), wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DEFAULT_STYLE);
|
|
||||||
auto tTest1 = m_mlc_folder->GetTextCtrl();
|
|
||||||
if(m_mlc_folder->HasTextCtrl())
|
|
||||||
{
|
|
||||||
m_mlc_folder->GetTextCtrl()->SetEditable(false);
|
|
||||||
m_mlc_folder->GetTextCtrl()->Bind(wxEVT_CHAR, &GettingStartedDialog::OnMLCPathChar, this);
|
|
||||||
}
|
|
||||||
mlc_path_sizer->Add(m_mlc_folder, 1, wxALL, 5);
|
|
||||||
|
|
||||||
mlc_path_sizer->Add(new wxStaticText(m_mlc_box_sizer->GetStaticBox(), wxID_ANY, _("(optional)")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
|
||||||
|
|
||||||
m_mlc_box_sizer->Add(mlc_path_sizer, 0, wxEXPAND, 5);
|
|
||||||
|
|
||||||
page1_sizer->Add(m_mlc_box_sizer, 0, wxALL | wxEXPAND, 5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// language selection
|
||||||
|
#if 0
|
||||||
{
|
{
|
||||||
auto* sizer = new wxStaticBoxSizer(wxVERTICAL, result, _("Game paths"));
|
m_page1.languageBoxSizer = new wxStaticBoxSizer(wxVERTICAL, mainPanel, _("Language"));
|
||||||
|
m_page1.languageText = new wxStaticText(m_page1.languageBoxSizer->GetStaticBox(), wxID_ANY, _("Select the language you want to use in Cemu"));
|
||||||
|
m_page1.languageBoxSizer->Add(m_page1.languageText, 0, wxALL, 5);
|
||||||
|
|
||||||
sizer->Add(new wxStaticText(sizer->GetStaticBox(), wxID_ANY, _("The game path is scanned by Cemu to locate your games. We recommend creating a dedicated directory in which\nyou place all your Wii U games. (example: C:\\wiiu\\games\\)\n\nYou can also set additional paths in the general settings of Cemu.")), 0, wxALL, 5);
|
wxString language_choices[] = { _("Default") };
|
||||||
|
wxChoice* m_language = new wxChoice(m_page1.languageBoxSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(language_choices), language_choices);
|
||||||
|
m_language->SetSelection(0);
|
||||||
|
|
||||||
|
for (const auto& language : wxGetApp().GetLanguages())
|
||||||
|
{
|
||||||
|
m_language->Append(language->DescriptionNative);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_language->SetSelection(0);
|
||||||
|
m_page1.languageBoxSizer->Add(m_language, 0, wxALL | wxEXPAND, 5);
|
||||||
|
|
||||||
|
page1_sizer->Add(m_page1.languageBoxSizer, 0, wxALL | wxEXPAND, 5);
|
||||||
|
|
||||||
|
m_language->Bind(wxEVT_CHOICE, [this, m_language](const auto&)
|
||||||
|
{
|
||||||
|
const auto language = m_language->GetStringSelection();
|
||||||
|
auto selection = m_language->GetSelection();
|
||||||
|
if (selection == 0)
|
||||||
|
GetConfig().language = wxLANGUAGE_DEFAULT;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto* app = (CemuApp*)wxTheApp;
|
||||||
|
const auto language = m_language->GetStringSelection();
|
||||||
|
for (const auto& lang : app->GetLanguages())
|
||||||
|
{
|
||||||
|
if (lang->DescriptionNative == language)
|
||||||
|
{
|
||||||
|
app->LocalizeUI(static_cast<wxLanguage>(lang->Language));
|
||||||
|
wxCommandEvent event(EVT_REFRESH_FIRST_PAGE);
|
||||||
|
wxPostEvent(this, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
m_page1.gamePathBoxSizer = new wxStaticBoxSizer(wxVERTICAL, mainPanel, _("Game paths"));
|
||||||
|
m_page1.gamePathText = new wxStaticText(m_page1.gamePathBoxSizer->GetStaticBox(), wxID_ANY, _("The game path is scanned by Cemu to automatically locate your games, game updates and DLCs. We recommend creating a dedicated directory in which\nyou place all your Wii U game files. Additional paths can be set later in Cemu's general settings. All common Wii U game formats are supported by Cemu."));
|
||||||
|
m_page1.gamePathBoxSizer->Add(m_page1.gamePathText, 0, wxALL, 5);
|
||||||
|
|
||||||
auto* game_path_sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto* game_path_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
game_path_sizer->Add(new wxStaticText(sizer->GetStaticBox(), wxID_ANY, _("Game path")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
m_page1.gamePathText2 = new wxStaticText(m_page1.gamePathBoxSizer->GetStaticBox(), wxID_ANY, _("Game path"));
|
||||||
|
game_path_sizer->Add(m_page1.gamePathText2, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||||
|
|
||||||
m_game_path = new wxDirPickerCtrl(sizer->GetStaticBox(), wxID_ANY, wxEmptyString, _("Select a folder"));
|
m_page1.gamePathPicker = new wxDirPickerCtrl(m_page1.gamePathBoxSizer->GetStaticBox(), wxID_ANY, wxEmptyString, _("Select a folder"));
|
||||||
game_path_sizer->Add(m_game_path, 1, wxALL, 5);
|
game_path_sizer->Add(m_page1.gamePathPicker, 1, wxALL, 5);
|
||||||
|
|
||||||
sizer->Add(game_path_sizer, 0, wxEXPAND, 5);
|
m_page1.gamePathBoxSizer->Add(game_path_sizer, 0, wxEXPAND, 5);
|
||||||
|
|
||||||
page1_sizer->Add(sizer, 0, wxALL | wxEXPAND, 5);
|
page1_sizer->Add(m_page1.gamePathBoxSizer, 0, wxALL | wxEXPAND, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto* sizer = new wxStaticBoxSizer(wxVERTICAL, result, _("Graphic packs"));
|
auto* sizer = new wxStaticBoxSizer(wxVERTICAL, mainPanel, _("Graphic packs && mods"));
|
||||||
|
|
||||||
sizer->Add(new wxStaticText(sizer->GetStaticBox(), wxID_ANY, _("Graphic packs improve games by offering the possibility to change resolution, tweak FPS or add other visual or gameplay modifications.\nDownload the community graphic packs to get started.\n")), 0, wxALL, 5);
|
sizer->Add(new wxStaticText(sizer->GetStaticBox(), wxID_ANY, _("Graphic packs improve games by offering the ability to change resolution, increase FPS, tweak visuals or add gameplay modifications.\nGet started by opening the graphic packs configuration window.\n")), 0, wxALL, 5);
|
||||||
|
|
||||||
auto* download_gp = new wxButton(sizer->GetStaticBox(), wxID_ANY, _("Download community graphic packs"));
|
auto* download_gp = new wxButton(sizer->GetStaticBox(), wxID_ANY, _("Download and configure graphic packs"));
|
||||||
download_gp->Bind(wxEVT_BUTTON, &GettingStartedDialog::OnDownloadGPs, this);
|
download_gp->Bind(wxEVT_BUTTON, &GettingStartedDialog::OnConfigureGPs, this);
|
||||||
sizer->Add(download_gp, 0, wxALIGN_CENTER | wxALL, 5);
|
sizer->Add(download_gp, 0, wxALIGN_CENTER | wxALL, 5);
|
||||||
|
|
||||||
page1_sizer->Add(sizer, 0, wxALL | wxEXPAND, 5);
|
page1_sizer->Add(sizer, 0, wxALL | wxEXPAND, 5);
|
||||||
@ -102,16 +127,15 @@ wxPanel* GettingStartedDialog::CreatePage1()
|
|||||||
sizer->SetFlexibleDirection(wxBOTH);
|
sizer->SetFlexibleDirection(wxBOTH);
|
||||||
sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL);
|
sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL);
|
||||||
|
|
||||||
auto* next = new wxButton(result, wxID_ANY, _("Next"), wxDefaultPosition, wxDefaultSize, 0);
|
auto* next = new wxButton(mainPanel, wxID_ANY, _("Next"), wxDefaultPosition, wxDefaultSize, 0);
|
||||||
next->Bind(wxEVT_BUTTON, [this](const auto&){m_notebook->SetSelection(1); });
|
next->Bind(wxEVT_BUTTON, [this](const auto&){m_notebook->SetSelection(1); });
|
||||||
sizer->Add(next, 0, wxALIGN_BOTTOM | wxALIGN_RIGHT | wxALL, 5);
|
sizer->Add(next, 0, wxALIGN_BOTTOM | wxALIGN_RIGHT | wxALL, 5);
|
||||||
|
|
||||||
page1_sizer->Add(sizer, 1, wxEXPAND, 5);
|
page1_sizer->Add(sizer, 1, wxEXPAND, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mainPanel->SetSizer(page1_sizer);
|
||||||
result->SetSizer(page1_sizer);
|
return mainPanel;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxPanel* GettingStartedDialog::CreatePage2()
|
wxPanel* GettingStartedDialog::CreatePage2()
|
||||||
@ -138,17 +162,17 @@ wxPanel* GettingStartedDialog::CreatePage2()
|
|||||||
option_sizer->SetFlexibleDirection(wxBOTH);
|
option_sizer->SetFlexibleDirection(wxBOTH);
|
||||||
option_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
|
option_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
|
||||||
|
|
||||||
m_fullscreen = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _("Start games with fullscreen"));
|
m_page2.fullscreenCheckbox = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _("Start games with fullscreen"));
|
||||||
option_sizer->Add(m_fullscreen, 0, wxALL, 5);
|
option_sizer->Add(m_page2.fullscreenCheckbox, 0, wxALL, 5);
|
||||||
|
|
||||||
m_separate = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _("Open separate pad screen"));
|
m_page2.separateCheckbox = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _("Open separate pad screen"));
|
||||||
option_sizer->Add(m_separate, 0, wxALL, 5);
|
option_sizer->Add(m_page2.separateCheckbox, 0, wxALL, 5);
|
||||||
|
|
||||||
m_update = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _("Automatically check for updates"));
|
m_page2.updateCheckbox = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _("Automatically check for updates"));
|
||||||
option_sizer->Add(m_update, 0, wxALL, 5);
|
option_sizer->Add(m_page2.updateCheckbox, 0, wxALL, 5);
|
||||||
#if BOOST_OS_LINUX
|
#if BOOST_OS_LINUX
|
||||||
if (!std::getenv("APPIMAGE")) {
|
if (!std::getenv("APPIMAGE")) {
|
||||||
m_update->Disable();
|
m_page2.updateCheckbox->Disable();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sizer->Add(option_sizer, 1, wxEXPAND, 5);
|
sizer->Add(option_sizer, 1, wxEXPAND, 5);
|
||||||
@ -162,10 +186,6 @@ wxPanel* GettingStartedDialog::CreatePage2()
|
|||||||
sizer->SetFlexibleDirection(wxBOTH);
|
sizer->SetFlexibleDirection(wxBOTH);
|
||||||
sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL);
|
sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL);
|
||||||
|
|
||||||
m_dont_show = new wxCheckBox(result, wxID_ANY, _("Don't show this again"));
|
|
||||||
m_dont_show->SetValue(true);
|
|
||||||
sizer->Add(m_dont_show, 0, wxALIGN_BOTTOM | wxALL, 5);
|
|
||||||
|
|
||||||
auto* previous = new wxButton(result, wxID_ANY, _("Previous"));
|
auto* previous = new wxButton(result, wxID_ANY, _("Previous"));
|
||||||
previous->Bind(wxEVT_BUTTON, [this](const auto&) {m_notebook->SetSelection(0); });
|
previous->Bind(wxEVT_BUTTON, [this](const auto&) {m_notebook->SetSelection(0); });
|
||||||
sizer->Add(previous, 0, wxALIGN_BOTTOM | wxALIGN_RIGHT | wxALL, 5);
|
sizer->Add(previous, 0, wxALIGN_BOTTOM | wxALIGN_RIGHT | wxALL, 5);
|
||||||
@ -184,23 +204,9 @@ wxPanel* GettingStartedDialog::CreatePage2()
|
|||||||
void GettingStartedDialog::ApplySettings()
|
void GettingStartedDialog::ApplySettings()
|
||||||
{
|
{
|
||||||
auto& config = GetConfig();
|
auto& config = GetConfig();
|
||||||
m_fullscreen->SetValue(config.fullscreen.GetValue());
|
m_page2.fullscreenCheckbox->SetValue(config.fullscreen.GetValue());
|
||||||
m_update->SetValue(config.check_update.GetValue());
|
m_page2.updateCheckbox->SetValue(config.check_update.GetValue());
|
||||||
m_separate->SetValue(config.pad_open.GetValue());
|
m_page2.separateCheckbox->SetValue(config.pad_open.GetValue());
|
||||||
m_dont_show->SetValue(true); // we want it always enabled by default
|
|
||||||
m_mlc_folder->SetPath(config.mlc_path.GetValue());
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const auto pconfig = PermanentConfig::Load();
|
|
||||||
if(!pconfig.custom_mlc_path.empty())
|
|
||||||
{
|
|
||||||
m_mlc_folder->SetPath(wxString::FromUTF8(pconfig.custom_mlc_path));
|
|
||||||
m_prev_mlc_warning->Show(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const PSDisabledException&) {}
|
|
||||||
catch (...) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GettingStartedDialog::UpdateWindowSize()
|
void GettingStartedDialog::UpdateWindowSize()
|
||||||
@ -219,46 +225,25 @@ void GettingStartedDialog::OnClose(wxCloseEvent& event)
|
|||||||
event.Skip();
|
event.Skip();
|
||||||
|
|
||||||
auto& config = GetConfig();
|
auto& config = GetConfig();
|
||||||
config.fullscreen = m_fullscreen->GetValue();
|
config.fullscreen = m_page2.fullscreenCheckbox->GetValue();
|
||||||
config.check_update = m_update->GetValue();
|
config.check_update = m_page2.updateCheckbox->GetValue();
|
||||||
config.pad_open = m_separate->GetValue();
|
config.pad_open = m_page2.separateCheckbox->GetValue();
|
||||||
config.did_show_graphic_pack_download = m_dont_show->GetValue();
|
|
||||||
|
|
||||||
const fs::path gamePath = wxHelper::MakeFSPath(m_game_path->GetPath());
|
const fs::path gamePath = wxHelper::MakeFSPath(m_page1.gamePathPicker->GetPath());
|
||||||
if (!gamePath.empty() && fs::exists(gamePath))
|
std::error_code ec;
|
||||||
|
if (!gamePath.empty() && fs::exists(gamePath, ec))
|
||||||
{
|
{
|
||||||
const auto it = std::find(config.game_paths.cbegin(), config.game_paths.cend(), gamePath);
|
const auto it = std::find(config.game_paths.cbegin(), config.game_paths.cend(), gamePath);
|
||||||
if (it == config.game_paths.cend())
|
if (it == config.game_paths.cend())
|
||||||
{
|
{
|
||||||
config.game_paths.emplace_back(_pathToUtf8(gamePath));
|
config.game_paths.emplace_back(_pathToUtf8(gamePath));
|
||||||
m_game_path_changed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fs::path mlcPath = wxHelper::MakeFSPath(m_mlc_folder->GetPath());
|
|
||||||
if(config.mlc_path.GetValue() != mlcPath && (mlcPath.empty() || fs::exists(mlcPath)))
|
|
||||||
{
|
|
||||||
config.SetMLCPath(mlcPath, false);
|
|
||||||
m_mlc_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_config.Save();
|
|
||||||
|
|
||||||
if(m_mlc_changed)
|
|
||||||
CemuApp::CreateDefaultFiles();
|
|
||||||
|
|
||||||
CafeTitleList::ClearScanPaths();
|
|
||||||
for (auto& it : GetConfig().game_paths)
|
|
||||||
CafeTitleList::AddScanPath(_utf8ToPath(it));
|
|
||||||
CafeTitleList::Refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GettingStartedDialog::GettingStartedDialog(wxWindow* parent)
|
GettingStartedDialog::GettingStartedDialog(wxWindow* parent)
|
||||||
: wxDialog(parent, wxID_ANY, _("Getting started"), wxDefaultPosition, { 740,530 }, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
: wxDialog(parent, wxID_ANY, _("Getting started"), wxDefaultPosition, { 740,530 }, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||||
{
|
{
|
||||||
//this->SetSizeHints(wxDefaultSize, { 740,530 });
|
|
||||||
|
|
||||||
auto* sizer = new wxBoxSizer(wxVERTICAL);
|
auto* sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
m_notebook = new wxSimplebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
|
m_notebook = new wxSimplebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
|
||||||
@ -279,19 +264,13 @@ GettingStartedDialog::GettingStartedDialog(wxWindow* parent)
|
|||||||
UpdateWindowSize();
|
UpdateWindowSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GettingStartedDialog::OnDownloadGPs(wxCommandEvent& event)
|
void GettingStartedDialog::OnConfigureGPs(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
DownloadGraphicPacksWindow dialog(this);
|
DownloadGraphicPacksWindow dialog(this);
|
||||||
dialog.ShowModal();
|
dialog.ShowModal();
|
||||||
|
|
||||||
GraphicPacksWindow2::RefreshGraphicPacks();
|
GraphicPacksWindow2::RefreshGraphicPacks();
|
||||||
|
|
||||||
wxMessageDialog ask_dialog(this, _("Do you want to view the downloaded graphic packs?"), _("Graphic packs"), wxCENTRE | wxYES_NO);
|
|
||||||
if (ask_dialog.ShowModal() == wxID_YES)
|
|
||||||
{
|
|
||||||
GraphicPacksWindow2 window(this, 0);
|
GraphicPacksWindow2 window(this, 0);
|
||||||
window.ShowModal();
|
window.ShowModal();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GettingStartedDialog::OnInputSettings(wxCommandEvent& event)
|
void GettingStartedDialog::OnInputSettings(wxCommandEvent& event)
|
||||||
@ -299,20 +278,3 @@ void GettingStartedDialog::OnInputSettings(wxCommandEvent& event)
|
|||||||
InputSettings2 dialog(this);
|
InputSettings2 dialog(this);
|
||||||
dialog.ShowModal();
|
dialog.ShowModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GettingStartedDialog::OnMLCPathChar(wxKeyEvent& event)
|
|
||||||
{
|
|
||||||
//if (LaunchSettings::GetMLCPath().has_value())
|
|
||||||
// return;
|
|
||||||
|
|
||||||
if (event.GetKeyCode() == WXK_DELETE || event.GetKeyCode() == WXK_BACK)
|
|
||||||
{
|
|
||||||
m_mlc_folder->GetTextCtrl()->SetValue(wxEmptyString);
|
|
||||||
if(m_prev_mlc_warning->IsShown())
|
|
||||||
{
|
|
||||||
m_prev_mlc_warning->Show(false);
|
|
||||||
UpdateWindowSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -13,9 +13,6 @@ class GettingStartedDialog : public wxDialog
|
|||||||
public:
|
public:
|
||||||
GettingStartedDialog(wxWindow* parent = nullptr);
|
GettingStartedDialog(wxWindow* parent = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] bool HasGamePathChanged() const { return m_game_path_changed; }
|
|
||||||
[[nodiscard]] bool HasMLCChanged() const { return m_mlc_changed; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wxPanel* CreatePage1();
|
wxPanel* CreatePage1();
|
||||||
wxPanel* CreatePage2();
|
wxPanel* CreatePage2();
|
||||||
@ -23,22 +20,29 @@ private:
|
|||||||
void UpdateWindowSize();
|
void UpdateWindowSize();
|
||||||
|
|
||||||
void OnClose(wxCloseEvent& event);
|
void OnClose(wxCloseEvent& event);
|
||||||
void OnDownloadGPs(wxCommandEvent& event);
|
void OnConfigureGPs(wxCommandEvent& event);
|
||||||
void OnInputSettings(wxCommandEvent& event);
|
void OnInputSettings(wxCommandEvent& event);
|
||||||
void OnMLCPathChar(wxKeyEvent& event);
|
|
||||||
|
|
||||||
wxSimplebook* m_notebook;
|
wxSimplebook* m_notebook;
|
||||||
wxCheckBox* m_fullscreen;
|
|
||||||
wxCheckBox* m_separate;
|
|
||||||
wxCheckBox* m_update;
|
|
||||||
wxCheckBox* m_dont_show;
|
|
||||||
|
|
||||||
wxStaticBoxSizer* m_mlc_box_sizer;
|
struct
|
||||||
wxStaticText* m_prev_mlc_warning;
|
{
|
||||||
wxDirPickerCtrl* m_mlc_folder;
|
// header
|
||||||
wxDirPickerCtrl* m_game_path;
|
wxStaticText* staticText11{};
|
||||||
|
wxStaticText* portableModeInfoText{};
|
||||||
|
|
||||||
bool m_game_path_changed = false;
|
// game path box
|
||||||
bool m_mlc_changed = false;
|
wxStaticBoxSizer* gamePathBoxSizer{};
|
||||||
|
wxStaticText* gamePathText{};
|
||||||
|
wxStaticText* gamePathText2{};
|
||||||
|
wxDirPickerCtrl* gamePathPicker{};
|
||||||
|
}m_page1;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
wxCheckBox* fullscreenCheckbox;
|
||||||
|
wxCheckBox* separateCheckbox;
|
||||||
|
wxCheckBox* updateCheckbox;
|
||||||
|
}m_page2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -149,8 +149,6 @@ enum
|
|||||||
// help
|
// help
|
||||||
MAINFRAME_MENU_ID_HELP_ABOUT = 21700,
|
MAINFRAME_MENU_ID_HELP_ABOUT = 21700,
|
||||||
MAINFRAME_MENU_ID_HELP_UPDATE,
|
MAINFRAME_MENU_ID_HELP_UPDATE,
|
||||||
MAINFRAME_MENU_ID_HELP_GETTING_STARTED,
|
|
||||||
|
|
||||||
// custom
|
// custom
|
||||||
MAINFRAME_ID_TIMER1 = 21800,
|
MAINFRAME_ID_TIMER1 = 21800,
|
||||||
};
|
};
|
||||||
@ -225,7 +223,6 @@ EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_TEXTURE_RELATIONS, MainWindow::OnDebugView
|
|||||||
// help menu
|
// help menu
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_HELP_ABOUT, MainWindow::OnHelpAbout)
|
EVT_MENU(MAINFRAME_MENU_ID_HELP_ABOUT, MainWindow::OnHelpAbout)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_HELP_UPDATE, MainWindow::OnHelpUpdate)
|
EVT_MENU(MAINFRAME_MENU_ID_HELP_UPDATE, MainWindow::OnHelpUpdate)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_HELP_GETTING_STARTED, MainWindow::OnHelpGettingStarted)
|
|
||||||
// misc
|
// misc
|
||||||
EVT_COMMAND(wxID_ANY, wxEVT_REQUEST_GAMELIST_REFRESH, MainWindow::OnRequestGameListRefresh)
|
EVT_COMMAND(wxID_ANY, wxEVT_REQUEST_GAMELIST_REFRESH, MainWindow::OnRequestGameListRefresh)
|
||||||
|
|
||||||
@ -418,25 +415,6 @@ wxString MainWindow::GetInitialWindowTitle()
|
|||||||
return BUILD_VERSION_WITH_NAME_STRING;
|
return BUILD_VERSION_WITH_NAME_STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ShowGettingStartedDialog()
|
|
||||||
{
|
|
||||||
GettingStartedDialog dia(this);
|
|
||||||
dia.ShowModal();
|
|
||||||
if (dia.HasGamePathChanged() || dia.HasMLCChanged())
|
|
||||||
m_game_list->ReloadGameEntries();
|
|
||||||
|
|
||||||
TogglePadView();
|
|
||||||
|
|
||||||
auto& config = GetConfig();
|
|
||||||
m_padViewMenuItem->Check(config.pad_open.GetValue());
|
|
||||||
m_fullscreenMenuItem->Check(config.fullscreen.GetValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace coreinit
|
|
||||||
{
|
|
||||||
void OSSchedulerEnd();
|
|
||||||
};
|
|
||||||
|
|
||||||
void MainWindow::OnClose(wxCloseEvent& event)
|
void MainWindow::OnClose(wxCloseEvent& event)
|
||||||
{
|
{
|
||||||
wxTheClipboard->Flush();
|
wxTheClipboard->Flush();
|
||||||
@ -2075,11 +2053,6 @@ void MainWindow::OnHelpUpdate(wxCommandEvent& event)
|
|||||||
test.ShowModal();
|
test.ShowModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::OnHelpGettingStarted(wxCommandEvent& event)
|
|
||||||
{
|
|
||||||
ShowGettingStartedDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::RecreateMenu()
|
void MainWindow::RecreateMenu()
|
||||||
{
|
{
|
||||||
if (m_menuBar)
|
if (m_menuBar)
|
||||||
@ -2304,7 +2277,6 @@ void MainWindow::RecreateMenu()
|
|||||||
m_check_update_menu->Enable(false);
|
m_check_update_menu->Enable(false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
helpMenu->Append(MAINFRAME_MENU_ID_HELP_GETTING_STARTED, _("&Getting started"));
|
|
||||||
helpMenu->AppendSeparator();
|
helpMenu->AppendSeparator();
|
||||||
helpMenu->Append(MAINFRAME_MENU_ID_HELP_ABOUT, _("&About Cemu"));
|
helpMenu->Append(MAINFRAME_MENU_ID_HELP_ABOUT, _("&About Cemu"));
|
||||||
|
|
||||||
|
@ -103,7 +103,6 @@ public:
|
|||||||
void OnAccountSelect(wxCommandEvent& event);
|
void OnAccountSelect(wxCommandEvent& event);
|
||||||
void OnConsoleLanguage(wxCommandEvent& event);
|
void OnConsoleLanguage(wxCommandEvent& event);
|
||||||
void OnHelpAbout(wxCommandEvent& event);
|
void OnHelpAbout(wxCommandEvent& event);
|
||||||
void OnHelpGettingStarted(wxCommandEvent& event);
|
|
||||||
void OnHelpUpdate(wxCommandEvent& event);
|
void OnHelpUpdate(wxCommandEvent& event);
|
||||||
void OnDebugSetting(wxCommandEvent& event);
|
void OnDebugSetting(wxCommandEvent& event);
|
||||||
void OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event);
|
void OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event);
|
||||||
@ -150,7 +149,6 @@ private:
|
|||||||
void RecreateMenu();
|
void RecreateMenu();
|
||||||
void UpdateChildWindowTitleRunningState();
|
void UpdateChildWindowTitleRunningState();
|
||||||
static wxString GetInitialWindowTitle();
|
static wxString GetInitialWindowTitle();
|
||||||
void ShowGettingStartedDialog();
|
|
||||||
|
|
||||||
bool InstallUpdate(const fs::path& metaFilePath);
|
bool InstallUpdate(const fs::path& metaFilePath);
|
||||||
|
|
||||||
|
14
src/main.cpp
14
src/main.cpp
@ -5,7 +5,6 @@
|
|||||||
#include "Cafe/OS/RPL/rpl.h"
|
#include "Cafe/OS/RPL/rpl.h"
|
||||||
#include "Cafe/OS/libs/gx2/GX2.h"
|
#include "Cafe/OS/libs/gx2/GX2.h"
|
||||||
#include "Cafe/OS/libs/coreinit/coreinit_Thread.h"
|
#include "Cafe/OS/libs/coreinit/coreinit_Thread.h"
|
||||||
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
|
|
||||||
#include "Cafe/GameProfile/GameProfile.h"
|
#include "Cafe/GameProfile/GameProfile.h"
|
||||||
#include "Cafe/GraphicPack/GraphicPack2.h"
|
#include "Cafe/GraphicPack/GraphicPack2.h"
|
||||||
#include "config/CemuConfig.h"
|
#include "config/CemuConfig.h"
|
||||||
@ -160,7 +159,7 @@ void ExpressionParser_test();
|
|||||||
void FSTVolumeTest();
|
void FSTVolumeTest();
|
||||||
void CRCTest();
|
void CRCTest();
|
||||||
|
|
||||||
void unitTests()
|
void UnitTests()
|
||||||
{
|
{
|
||||||
ExpressionParser_test();
|
ExpressionParser_test();
|
||||||
gx2CopySurfaceTest();
|
gx2CopySurfaceTest();
|
||||||
@ -169,17 +168,6 @@ void unitTests()
|
|||||||
CRCTest();
|
CRCTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
int mainEmulatorHLE()
|
|
||||||
{
|
|
||||||
LatteOverlay_init();
|
|
||||||
// run a couple of tests if in non-release mode
|
|
||||||
#ifdef CEMU_DEBUG_ASSERT
|
|
||||||
unitTests();
|
|
||||||
#endif
|
|
||||||
CemuCommonInit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isConsoleConnected = false;
|
bool isConsoleConnected = false;
|
||||||
void requireConsole()
|
void requireConsole()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user