Compare commits
No commits in common. "d0716d624281b35365040e3b65faa3ac24945286" and "e2d473da441a0eb49601b8b844f8a7c3d772f062" have entirely different histories.
d0716d6242
...
e2d473da44
14 changed files with 28 additions and 508 deletions
8
.gitmodules
vendored
8
.gitmodules
vendored
|
@ -26,11 +26,3 @@
|
||||||
path = third-party/efsw
|
path = third-party/efsw
|
||||||
url = https://github.com/SpartanJ/efsw
|
url = https://github.com/SpartanJ/efsw
|
||||||
branch = master
|
branch = master
|
||||||
[submodule "third-party/cpr"]
|
|
||||||
path = third-party/cpr
|
|
||||||
url = https://github.com/whoshuu/cpr
|
|
||||||
branch = master
|
|
||||||
[submodule "json.hpp"]
|
|
||||||
path = third-party/json
|
|
||||||
url = https://github.com/nlohmann/json
|
|
||||||
branch = master
|
|
||||||
|
|
|
@ -88,11 +88,4 @@ set(BUILD_TEST_APP OFF CACHE BOOL "" FORCE)
|
||||||
set(EFSW_INSTALL OFF CACHE BOOL "" FORCE)
|
set(EFSW_INSTALL OFF CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/efsw EXCLUDE_FROM_ALL)
|
add_subdirectory(third-party/efsw EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
set(CPR_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
|
||||||
set(CMAKE_USE_LIBSSH2 OFF CACHE BOOL "" FORCE) # For some reason, even when HTTP_ONLY is set to ON, libcurl will try to link to libssh2.
|
|
||||||
add_subdirectory(third-party/cpr EXCLUDE_FROM_ALL)
|
|
||||||
|
|
||||||
set(JSON_BuildTests OFF CACHE BOOL "" FORCE)
|
|
||||||
add_subdirectory(third-party/json)
|
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
|
@ -46,8 +46,6 @@ add_executable(MassBuilderSaveTool WIN32
|
||||||
Mass/Mass.cpp
|
Mass/Mass.cpp
|
||||||
Maps/LastMissionId.h
|
Maps/LastMissionId.h
|
||||||
Maps/StoryProgress.h
|
Maps/StoryProgress.h
|
||||||
ToastQueue/ToastQueue.h
|
|
||||||
ToastQueue/ToastQueue.cpp
|
|
||||||
FontAwesome/IconsFontAwesome5.h
|
FontAwesome/IconsFontAwesome5.h
|
||||||
FontAwesome/IconsFontAwesome5Brands.h
|
FontAwesome/IconsFontAwesome5Brands.h
|
||||||
resource.rc
|
resource.rc
|
||||||
|
@ -77,7 +75,5 @@ target_link_libraries(MassBuilderSaveTool PRIVATE
|
||||||
MagnumIntegration::ImGui
|
MagnumIntegration::ImGui
|
||||||
efsw
|
efsw
|
||||||
zip
|
zip
|
||||||
cpr::cpr
|
|
||||||
nlohmann_json::nlohmann_json
|
|
||||||
imm32
|
imm32
|
||||||
wtsapi32)
|
wtsapi32)
|
||||||
|
|
|
@ -30,10 +30,6 @@
|
||||||
#include <Magnum/ImGuiIntegration/Integration.h>
|
#include <Magnum/ImGuiIntegration/Integration.h>
|
||||||
#include <Magnum/ImGuiIntegration/Context.hpp>
|
#include <Magnum/ImGuiIntegration/Context.hpp>
|
||||||
|
|
||||||
#include <cpr/cpr.h>
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
#include <windef.h>
|
#include <windef.h>
|
||||||
#include <winuser.h>
|
#include <winuser.h>
|
||||||
#include <processthreadsapi.h>
|
#include <processthreadsapi.h>
|
||||||
|
@ -85,15 +81,12 @@ SaveTool::SaveTool(const Arguments& arguments):
|
||||||
|
|
||||||
initialiseGui();
|
initialiseGui();
|
||||||
|
|
||||||
if((_initEventId = SDL_RegisterEvents(2)) == UnsignedInt(-1)) {
|
if((_initEventId = SDL_RegisterEvents(1)) == UnsignedInt(-1)) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
"SDL_RegisterEvents failed in SaveTool::SaveTool(). Exiting...", window());
|
"SDL_RegisterEvents failed in SaveTool::SaveTool(). Exiting...", window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateEventId = _initEventId + 1;
|
|
||||||
|
|
||||||
_backupsDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "backups");
|
_backupsDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "backups");
|
||||||
_stagingDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "staging");
|
_stagingDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "staging");
|
||||||
|
|
||||||
|
@ -108,7 +101,6 @@ SaveTool::SaveTool(const Arguments& arguments):
|
||||||
if(!findGameDataDirectory()) {
|
if(!findGameDataDirectory()) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", _lastError.c_str(), window());
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", _lastError.c_str(), window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_configDir = Utility::Directory::join(_gameDataDir, "Saved/Config/WindowsNoEditor");
|
_configDir = Utility::Directory::join(_gameDataDir, "Saved/Config/WindowsNoEditor");
|
||||||
|
@ -118,7 +110,6 @@ SaveTool::SaveTool(const Arguments& arguments):
|
||||||
if(SDL_InitSubSystem(SDL_INIT_TIMER) != 0) {
|
if(SDL_InitSubSystem(SDL_INIT_TIMER) != 0) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", SDL_GetError(), window());
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", SDL_GetError(), window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkGameState();
|
checkGameState();
|
||||||
|
@ -131,23 +122,11 @@ SaveTool::SaveTool(const Arguments& arguments):
|
||||||
if(_gameCheckTimerId == 0) {
|
if(_gameCheckTimerId == 0) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), window());
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialiseConfiguration();
|
|
||||||
|
|
||||||
if(_checkUpdatesOnStartup) {
|
|
||||||
_thread = std::thread{[this]{ checkForUpdates(); }};
|
|
||||||
_queue.addToast(Toast::Type::Default, "Checking for updates...");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveTool::~SaveTool() {
|
SaveTool::~SaveTool() {
|
||||||
SDL_RemoveTimer(_gameCheckTimerId);
|
SDL_RemoveTimer(_gameCheckTimerId);
|
||||||
|
|
||||||
_conf.setValue("unsafe_mode", _unsafeMode);
|
|
||||||
_conf.setValue("startup_update_check", _checkUpdatesOnStartup);
|
|
||||||
_conf.save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
||||||
|
@ -268,9 +247,6 @@ void SaveTool::anyEvent(SDL_Event& event) {
|
||||||
if(event.type == _initEventId) {
|
if(event.type == _initEventId) {
|
||||||
initEvent(event);
|
initEvent(event);
|
||||||
}
|
}
|
||||||
else if(event.type == _updateEventId) {
|
|
||||||
updateCheckEvent(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::initEvent(SDL_Event& event) {
|
void SaveTool::initEvent(SDL_Event& event) {
|
||||||
|
@ -290,90 +266,6 @@ void SaveTool::initEvent(SDL_Event& event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::updateCheckEvent(SDL_Event& event) {
|
|
||||||
_thread.join();
|
|
||||||
|
|
||||||
cpr::Response r{std::move(*static_cast<cpr::Response*>(event.user.data1))};
|
|
||||||
delete static_cast<cpr::Response*>(event.user.data1);
|
|
||||||
|
|
||||||
if(r.elapsed > 10.0) {
|
|
||||||
_queue.addToast(Toast::Type::Error, "The request timed out.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(r.status_code != 200) {
|
|
||||||
_queue.addToast(Toast::Type::Error, Utility::formatString("The request failed with error code {}: {}", r.status_code, r.reason));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
json response = json::parse(r.text);
|
|
||||||
|
|
||||||
struct Version {
|
|
||||||
explicit Version(const std::string& str) {
|
|
||||||
std::size_t start_point = 0;
|
|
||||||
|
|
||||||
if(str[0] == 'v') {
|
|
||||||
start_point++;
|
|
||||||
}
|
|
||||||
|
|
||||||
major = std::atoi(str.c_str() + start_point);
|
|
||||||
start_point = str.find('.', start_point) + 1;
|
|
||||||
minor = std::atoi(str.c_str() + start_point);
|
|
||||||
start_point = str.find('.', start_point) + 1;
|
|
||||||
patch = std::atoi(str.c_str() + start_point);
|
|
||||||
}
|
|
||||||
Int major;
|
|
||||||
Int minor;
|
|
||||||
Int patch;
|
|
||||||
|
|
||||||
bool operator==(const Version& other) const {
|
|
||||||
return (major == other.major) && (minor == other.minor) && (patch == other.patch);
|
|
||||||
}
|
|
||||||
bool operator>(const Version& other) const {
|
|
||||||
return ( major * 10000 + minor * 100 + patch) >
|
|
||||||
(other.major * 10000 + other.minor * 100 + other.patch);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Version current_ver{SAVETOOL_VERSION};
|
|
||||||
Version latest_ver{response[0]["tag_name"]};
|
|
||||||
|
|
||||||
if(latest_ver == current_ver) {
|
|
||||||
_queue.addToast(Toast::Type::Success, "The application is already up to date.");
|
|
||||||
}
|
|
||||||
else if(latest_ver > current_ver) {
|
|
||||||
_queue.addToast(Toast::Type::Warning, "Your version is out of date.\nCheck the settings for more information.",
|
|
||||||
std::chrono::milliseconds{5000});
|
|
||||||
_updateAvailable = true;
|
|
||||||
_latestVersion = Utility::formatString("{}.{}.{}", latest_ver.major, latest_ver.minor, latest_ver.patch);
|
|
||||||
_releaseLink = response[0]["html_url"];
|
|
||||||
_downloadLink = response[0]["assets"][0]["browser_download_url"];
|
|
||||||
}
|
|
||||||
else if(current_ver > latest_ver) {
|
|
||||||
_queue.addToast(Toast::Type::Warning, "Your version is more recent than the latest one in the repo. How???");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::initialiseConfiguration() {
|
|
||||||
if(_conf.hasValue("unsafe_mode")) {
|
|
||||||
_unsafeMode = _conf.value<bool>("unsafe_mode");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_conf.setValue("unsafe_mode", _unsafeMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_conf.hasValue("startup_update_check")) {
|
|
||||||
_checkUpdatesOnStartup = _conf.value<bool>("startup_update_check");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_conf.setValue("startup_update_check", _checkUpdatesOnStartup);
|
|
||||||
}
|
|
||||||
|
|
||||||
_conf.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::initialiseGui() {
|
void SaveTool::initialiseGui() {
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
|
|
||||||
|
@ -523,15 +415,13 @@ void SaveTool::drawGui() {
|
||||||
ImGui::ShowMetricsWindow(&_metricsWindow);
|
ImGui::ShowMetricsWindow(&_metricsWindow);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_queue.draw(windowSize());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawDisclaimer() {
|
void SaveTool::drawDisclaimer() {
|
||||||
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
||||||
|
|
||||||
if(ImGui::Begin("Disclaimer##DisclaimerWindow", nullptr,
|
if(ImGui::Begin("Disclaimer##DisclaimerWindow", nullptr,
|
||||||
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoBringToFrontOnFocus|
|
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|
|
||||||
ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_MenuBar))
|
ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_MenuBar))
|
||||||
{
|
{
|
||||||
if(ImGui::BeginMenuBar()) {
|
if(ImGui::BeginMenuBar()) {
|
||||||
|
@ -659,15 +549,3 @@ void SaveTool::checkGameState() {
|
||||||
_gameState = GameState::Unknown;
|
_gameState = GameState::Unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::checkForUpdates() {
|
|
||||||
cpr::Response r = cpr::Get(cpr::Url{"https://williamjcm.ovh/git/api/v1/repos/williamjcm/MassBuilderSaveTool/releases"},
|
|
||||||
cpr::Parameters{{"limit", "1"}}, cpr::Timeout{10000});
|
|
||||||
|
|
||||||
SDL_Event event;
|
|
||||||
SDL_zero(event);
|
|
||||||
event.type = _updateEventId;
|
|
||||||
event.user.code = r.status_code;
|
|
||||||
event.user.data1 = new cpr::Response{std::move(r)};
|
|
||||||
SDL_PushEvent(&event);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <Corrade/Containers/Pointer.h>
|
#include <Corrade/Containers/Pointer.h>
|
||||||
#include <Corrade/Utility/Configuration.h>
|
|
||||||
#include <Corrade/Utility/Resource.h>
|
#include <Corrade/Utility/Resource.h>
|
||||||
|
|
||||||
#include <Magnum/Platform/Sdl2Application.h>
|
#include <Magnum/Platform/Sdl2Application.h>
|
||||||
|
@ -34,7 +33,6 @@
|
||||||
|
|
||||||
#include "../ProfileManager/ProfileManager.h"
|
#include "../ProfileManager/ProfileManager.h"
|
||||||
#include "../MassManager/MassManager.h"
|
#include "../MassManager/MassManager.h"
|
||||||
#include "../ToastQueue/ToastQueue.h"
|
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
@ -72,10 +70,8 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
ProfileManagerFailure
|
ProfileManagerFailure
|
||||||
};
|
};
|
||||||
void initEvent(SDL_Event& event);
|
void initEvent(SDL_Event& event);
|
||||||
void updateCheckEvent(SDL_Event& event);
|
|
||||||
|
|
||||||
// Initialisation methods
|
// Initialisation methods
|
||||||
void initialiseConfiguration();
|
|
||||||
void initialiseGui();
|
void initialiseGui();
|
||||||
void initialiseManager();
|
void initialiseManager();
|
||||||
auto findGameDataDirectory() -> bool;
|
auto findGameDataDirectory() -> bool;
|
||||||
|
@ -140,9 +136,6 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
|
|
||||||
void checkGameState();
|
void checkGameState();
|
||||||
|
|
||||||
void checkForUpdates();
|
|
||||||
|
|
||||||
Utility::Configuration _conf{"MassBuilderSaveTool.ini"};
|
|
||||||
Utility::Resource _rs{"assets"};
|
Utility::Resource _rs{"assets"};
|
||||||
|
|
||||||
// GUI-related members
|
// GUI-related members
|
||||||
|
@ -162,12 +155,8 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
bool _metricsWindow{false};
|
bool _metricsWindow{false};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ToastQueue _queue;
|
std::thread _thread;
|
||||||
|
|
||||||
std::thread _thread; // used for threaded operations such as profile manager init or update checking.
|
|
||||||
|
|
||||||
UnsignedInt _initEventId;
|
UnsignedInt _initEventId;
|
||||||
UnsignedInt _updateEventId;
|
|
||||||
|
|
||||||
std::string _lastError;
|
std::string _lastError;
|
||||||
|
|
||||||
|
@ -197,11 +186,5 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
};
|
};
|
||||||
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
|
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
|
||||||
|
|
||||||
bool _checkUpdatesOnStartup{true};
|
|
||||||
bool _unsafeMode{false};
|
bool _unsafeMode{false};
|
||||||
|
|
||||||
bool _updateAvailable{false};
|
|
||||||
std::string _latestVersion;
|
|
||||||
std::string _releaseLink;
|
|
||||||
std::string _downloadLink;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,6 +42,12 @@ void SaveTool::drawManager() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ImGui::BeginTable("##TopRow", 2)) {
|
||||||
|
ImGui::TableSetupColumn("##ProfileInfo", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
ImGui::TableSetupColumn("##Unsafe", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
ImGui::Text("Current profile: %s (%s)",
|
ImGui::Text("Current profile: %s (%s)",
|
||||||
_currentProfile->companyName().c_str(),
|
_currentProfile->companyName().c_str(),
|
||||||
|
@ -54,6 +60,14 @@ void SaveTool::drawManager() {
|
||||||
_uiState = UiState::ProfileManager;
|
_uiState = UiState::ProfileManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
ImGui::Checkbox("Unsafe mode", &_unsafeMode);
|
||||||
|
drawTooltip("Enabling this allows interactions deemed to be unsafe to do while the game is running.",
|
||||||
|
Float(windowSize().x()) * 0.35f);
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
if(ImGui::BeginChild("##ProfileInfo",
|
if(ImGui::BeginChild("##ProfileInfo",
|
||||||
{ImGui::GetContentRegionAvailWidth() * 0.60f, 0.0f},
|
{ImGui::GetContentRegionAvailWidth() * 0.60f, 0.0f},
|
||||||
true, ImGuiWindowFlags_MenuBar))
|
true, ImGuiWindowFlags_MenuBar))
|
||||||
|
|
|
@ -27,7 +27,7 @@ void SaveTool::drawProfileManager() {
|
||||||
|
|
||||||
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
||||||
if(ImGui::Begin("Profile management##ProfileManager", nullptr,
|
if(ImGui::Begin("Profile management##ProfileManager", nullptr,
|
||||||
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoBringToFrontOnFocus|
|
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_AlwaysAutoResize|
|
||||||
ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_MenuBar))
|
ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_MenuBar))
|
||||||
{
|
{
|
||||||
if(ImGui::BeginMenuBar()) {
|
if(ImGui::BeginMenuBar()) {
|
||||||
|
|
|
@ -251,58 +251,6 @@ void SaveTool::drawAbout() {
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::TreeNodeEx("C++ Requests (cpr)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
|
||||||
ImGui::AlignTextToFramePadding();
|
|
||||||
const char* cpr_website = "https://whoshuu.github.io/cpr/";
|
|
||||||
ImGui::Text(ICON_FA_GLOBE " %s", cpr_website);
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button("Copy to clipboard")) {
|
|
||||||
ImGui::SetClipboardText(cpr_website);
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button("Open in browser")) {
|
|
||||||
openUri(cpr_website);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
|
||||||
|
|
||||||
static const auto cpr_licence = _rs.get("LICENSE.cpr");
|
|
||||||
if(ImGui::BeginChild("##cprLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
|
||||||
ImGui::TextUnformatted(cpr_licence.c_str());
|
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::TreePop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui::TreeNodeEx("JSON for Modern C++ (aka json.hpp)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
|
||||||
ImGui::AlignTextToFramePadding();
|
|
||||||
const char* json_website = "https://json.nlohmann.me/";
|
|
||||||
ImGui::Text(ICON_FA_GLOBE " %s", json_website);
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button("Copy to clipboard")) {
|
|
||||||
ImGui::SetClipboardText(json_website);
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button("Open in browser")) {
|
|
||||||
openUri(json_website);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
|
||||||
|
|
||||||
static const auto json_licence = _rs.get("LICENSE.json");
|
|
||||||
if(ImGui::BeginChild("##jsonLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
|
||||||
ImGui::TextUnformatted(json_licence.c_str());
|
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::TreePop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui::TreeNodeEx("Font Awesome", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
if(ImGui::TreeNodeEx("Font Awesome", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||||
ImGui::TextUnformatted("Version used: 5.15.3");
|
ImGui::TextUnformatted("Version used: 5.15.3");
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
|
|
|
@ -54,36 +54,6 @@ void SaveTool::drawMainMenu() {
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if(ImGui::BeginMenu(ICON_FA_COG " Settings")) {
|
|
||||||
ImGui::Checkbox("Unsafe mode", &_unsafeMode);
|
|
||||||
ImGui::SameLine();
|
|
||||||
drawHelpMarker("This allows changing the state of save files in the game's save folder even when the game is running.",
|
|
||||||
Float(windowSize().x()) * 0.4f);
|
|
||||||
|
|
||||||
ImGui::Checkbox("Check for updates on startup", &_checkUpdatesOnStartup);
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button(ICON_FA_SYNC_ALT " Check now")) {
|
|
||||||
_queue.addToast(Toast::Type::Default, "Checking for updates...");
|
|
||||||
_thread = std::thread{[this]{ checkForUpdates(); }};
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_updateAvailable) {
|
|
||||||
ImGui::AlignTextToFramePadding();
|
|
||||||
ImGui::Text("Version %s is available.", _latestVersion.c_str());
|
|
||||||
if(ImGui::Button(ICON_FA_FILE_SIGNATURE " Release notes")) {
|
|
||||||
openUri(_releaseLink);
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button(ICON_FA_DOWNLOAD " Download now")) {
|
|
||||||
openUri(_downloadLink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
if(ImGui::MenuItem(ICON_FA_SIGN_OUT_ALT " Quit##QuitMenuItem")) {
|
if(ImGui::MenuItem(ICON_FA_SIGN_OUT_ALT " Quit##QuitMenuItem")) {
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,162 +0,0 @@
|
||||||
// MassBuilderSaveTool
|
|
||||||
// Copyright (C) 2021 Guillaume Jacquemin
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include <Corrade/Utility/FormatStl.h>
|
|
||||||
|
|
||||||
#include <Magnum/Math/Functions.h>
|
|
||||||
|
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
|
||||||
|
|
||||||
#include "ToastQueue.h"
|
|
||||||
|
|
||||||
using namespace Corrade;
|
|
||||||
|
|
||||||
constexpr UnsignedInt success_colour = 0xff67d23bu;
|
|
||||||
constexpr UnsignedInt info_colour = 0xffcc832fu;
|
|
||||||
constexpr UnsignedInt warning_colour = 0xff2fcfc7u;
|
|
||||||
constexpr UnsignedInt error_colour = 0xff3134cdu;
|
|
||||||
|
|
||||||
constexpr UnsignedInt fade_time = 150;
|
|
||||||
constexpr Float base_opacity = 1.0f;
|
|
||||||
constexpr Vector2 padding{20.0f, 20.0f};
|
|
||||||
constexpr Float toast_spacing = 10.0f;
|
|
||||||
|
|
||||||
Toast::Toast(Type type, const std::string& message, std::chrono::milliseconds timeout):
|
|
||||||
_type{type}, _message{message}, _timeout{timeout}, _creationTime{std::chrono::steady_clock::now()}
|
|
||||||
{
|
|
||||||
_phaseTrack = Animation::Track<UnsignedInt, Phase>{{
|
|
||||||
{0, Phase::FadeIn},
|
|
||||||
{fade_time, Phase::Wait},
|
|
||||||
{fade_time + timeout.count(), Phase::FadeOut},
|
|
||||||
{(fade_time * 2) + timeout.count(), Phase::TimedOut}
|
|
||||||
}, Math::select, Animation::Extrapolation::Constant};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Toast::type() -> Type {
|
|
||||||
return _type;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Toast::message() -> const std::string& {
|
|
||||||
return _message;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Toast::timeout() -> std::chrono::milliseconds {
|
|
||||||
return _timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Toast::creationTime() -> std::chrono::steady_clock::time_point {
|
|
||||||
return _creationTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Toast::elapsedTime() -> std::chrono::milliseconds {
|
|
||||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - _creationTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Toast::phase() -> Phase {
|
|
||||||
return _phaseTrack.at(elapsedTime().count());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Toast::opacity() -> Float {
|
|
||||||
Phase phase = this->phase();
|
|
||||||
Long elapsed_time = elapsedTime().count();
|
|
||||||
|
|
||||||
if(phase == Phase::FadeIn) {
|
|
||||||
return Float(elapsed_time) / Float(fade_time);
|
|
||||||
}
|
|
||||||
else if(phase == Phase::FadeOut) {
|
|
||||||
return 1.0f - ((Float(elapsed_time) - Float(fade_time) - Float(_timeout.count())) / Float(fade_time));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToastQueue::addToast(Toast&& toast) {
|
|
||||||
_toasts.push_back(std::move(toast));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToastQueue::addToast(Toast::Type type, const std::string& message, std::chrono::milliseconds timeout) {
|
|
||||||
_toasts.emplace_back(type, message, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToastQueue::draw(Vector2i viewport_size) {
|
|
||||||
Float height = 0.0f;
|
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < _toasts.size(); i++) {
|
|
||||||
Toast* current = &_toasts[i];
|
|
||||||
|
|
||||||
if(current->phase() == Toast::Phase::TimedOut) {
|
|
||||||
removeToast(i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string win_id = Utility::formatString("##Toast{}", i);
|
|
||||||
|
|
||||||
Float opacity = base_opacity * current->opacity();
|
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, opacity);
|
|
||||||
|
|
||||||
ImGui::SetNextWindowPos({viewport_size.x() - padding.x(), viewport_size.y() - padding.y() - height}, ImGuiCond_Always, {1.0f, 1.0f});
|
|
||||||
if(ImGui::Begin(win_id.c_str(), nullptr,
|
|
||||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoDecoration|
|
|
||||||
ImGuiWindowFlags_NoInputs|ImGuiWindowFlags_NoNav|ImGuiWindowFlags_NoFocusOnAppearing))
|
|
||||||
{
|
|
||||||
ImColor colour = 0xffffffff;
|
|
||||||
|
|
||||||
switch(current->type()) {
|
|
||||||
case Toast::Type::Default:
|
|
||||||
break;
|
|
||||||
case Toast::Type::Success:
|
|
||||||
colour = success_colour;
|
|
||||||
ImGui::TextColored(colour, ICON_FA_CHECK_CIRCLE);
|
|
||||||
break;
|
|
||||||
case Toast::Type::Info:
|
|
||||||
colour = info_colour;
|
|
||||||
ImGui::TextColored(colour, ICON_FA_INFO_CIRCLE);
|
|
||||||
break;
|
|
||||||
case Toast::Type::Warning:
|
|
||||||
colour = warning_colour;
|
|
||||||
ImGui::TextColored(colour, ICON_FA_EXCLAMATION_TRIANGLE);
|
|
||||||
break;
|
|
||||||
case Toast::Type::Error:
|
|
||||||
colour = error_colour;
|
|
||||||
ImGui::TextColored(colour, ICON_FA_TIMES_CIRCLE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(current->type() != Toast::Type::Default) {
|
|
||||||
ImGui::SameLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(current->message().length() > 127) {
|
|
||||||
ImGui::TextColored(colour, "%.*s...", 127, current->message().c_str());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ImGui::TextColored(colour, current->message().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
height += ImGui::GetWindowHeight() + toast_spacing;
|
|
||||||
}
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
ImGui::PopStyleVar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToastQueue::removeToast(Long index) {
|
|
||||||
_toasts.erase(_toasts.begin() + index);
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
|
||||||
// Copyright (C) 2021 Guillaume Jacquemin
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <Magnum/Magnum.h>
|
|
||||||
#include <Magnum/Animation/Track.h>
|
|
||||||
|
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
class Toast {
|
|
||||||
public:
|
|
||||||
enum class Type : UnsignedByte {
|
|
||||||
Default, Success, Info, Warning, Error
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Phase : UnsignedByte {
|
|
||||||
FadeIn, Wait, FadeOut, TimedOut
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit Toast(Type type, const std::string& message,
|
|
||||||
std::chrono::milliseconds timeout = std::chrono::milliseconds{3000});
|
|
||||||
|
|
||||||
Toast(const Toast& other) = delete;
|
|
||||||
Toast& operator=(const Toast& other) = delete;
|
|
||||||
|
|
||||||
Toast(Toast&& other) = default;
|
|
||||||
Toast& operator=(Toast&& other) = default;
|
|
||||||
|
|
||||||
auto type() -> Type;
|
|
||||||
|
|
||||||
auto message() -> std::string const&;
|
|
||||||
|
|
||||||
auto timeout() -> std::chrono::milliseconds;
|
|
||||||
|
|
||||||
auto creationTime() -> std::chrono::steady_clock::time_point;
|
|
||||||
|
|
||||||
auto elapsedTime() -> std::chrono::milliseconds;
|
|
||||||
|
|
||||||
auto phase() -> Phase;
|
|
||||||
|
|
||||||
auto opacity() -> Float;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Type _type{Type::Default};
|
|
||||||
std::string _message;
|
|
||||||
std::chrono::milliseconds _timeout;
|
|
||||||
std::chrono::steady_clock::time_point _creationTime;
|
|
||||||
Animation::Track<UnsignedInt, Phase> _phaseTrack;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ToastQueue {
|
|
||||||
public:
|
|
||||||
void addToast(Toast&& toast);
|
|
||||||
|
|
||||||
void addToast(Toast::Type type, const std::string& message,
|
|
||||||
std::chrono::milliseconds timeout = std::chrono::milliseconds{3000});
|
|
||||||
|
|
||||||
void draw(Vector2i viewport_size);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void removeToast(Long index);
|
|
||||||
|
|
||||||
std::vector<Toast> _toasts;
|
|
||||||
};
|
|
|
@ -43,11 +43,3 @@ alias=LICENSE.libzip
|
||||||
[file]
|
[file]
|
||||||
filename=../third-party/efsw/LICENSE
|
filename=../third-party/efsw/LICENSE
|
||||||
alias=LICENSE.efsw
|
alias=LICENSE.efsw
|
||||||
|
|
||||||
[file]
|
|
||||||
filename=../third-party/cpr/LICENSE
|
|
||||||
alias=LICENSE.cpr
|
|
||||||
|
|
||||||
[file]
|
|
||||||
filename=../third-party/json/LICENSE.MIT
|
|
||||||
alias=LICENSE.json
|
|
||||||
|
|
1
third-party/cpr
vendored
1
third-party/cpr
vendored
|
@ -1 +0,0 @@
|
||||||
Subproject commit 814bd0926379cfc786dd1d9df9ce266a4bb6cf59
|
|
1
third-party/json
vendored
1
third-party/json
vendored
|
@ -1 +0,0 @@
|
||||||
Subproject commit 350ff4f7ced7c4117eae2fb93df02823c8021fcb
|
|
Loading…
Reference in a new issue