diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2e65dcc..f69f00b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -139,6 +139,8 @@ add_executable(MassBuilderSaveTool WIN32 SaveTool/SaveTool_MassViewer_Weapons.cpp SaveTool/SaveTool_ProfileManager.cpp SaveTool/SaveTool_UpdateChecker.cpp + Configuration/Configuration.h + Configuration/Configuration.cpp ProfileManager/ProfileManager.h ProfileManager/ProfileManager.cpp Profile/Profile.h diff --git a/src/Configuration/Configuration.cpp b/src/Configuration/Configuration.cpp new file mode 100644 index 0000000..c8e1c49 --- /dev/null +++ b/src/Configuration/Configuration.cpp @@ -0,0 +1,152 @@ +#include +#include +#include + +#include "Configuration.h" + +Configuration::Configuration() { + Containers::String exe_path = Utility::Path::split(*Utility::Path::executableLocation()).first(); + _conf = Utility::Configuration{Utility::Path::join(exe_path, "MassBuilderSaveTool.ini")}; + + if(_conf.hasValue("swap_interval")) { + _swapInterval = _conf.value("swap_interval"); + } + else { + _conf.setValue("swap_interval", 1); + } + + if(_conf.hasValue("frame_limit")) { + std::string frame_limit = _conf.value("frame_limit"); + if(frame_limit == "half_vsync") { + _swapInterval = 2; + } + _conf.removeValue("frame_limit"); + } + + if(_conf.hasValue("fps_cap")) { + _fpsCap = _conf.value("fps_cap"); + } + else { + _conf.setValue("fps_cap", 60.0f); + } + + if(_conf.hasValue("cheat_mode")) { + _cheatMode = _conf.value("cheat_mode"); + } + else { + _conf.setValue("cheat_mode", _cheatMode); + } + + if(_conf.hasValue("advanced_mode")) { + _advancedMode = _conf.value("advanced_mode"); + } + else { + _conf.setValue("advanced_mode", _advancedMode); + } + + if(_conf.hasValue("startup_update_check")) { + _checkUpdatesOnStartup = _conf.value("startup_update_check"); + } + else { + _conf.setValue("startup_update_check", _checkUpdatesOnStartup); + } + + if(_conf.hasValue("skip_disclaimer")) { + _skipDisclaimer = _conf.value("skip_disclaimer"); + } + else { + _conf.setValue("skip_disclaimer", _skipDisclaimer); + } +} + +Configuration::~Configuration() { + save(); +} + +void +Configuration::save() { + _conf.save(); +} + +int +Configuration::swapInterval() const { + return _swapInterval; +} + +void +Configuration::setSwapInterval(int interval) { + _swapInterval = interval; + _conf.setValue("swap_interval", _swapInterval); + _conf.save(); +} + +float +Configuration::fpsCap() const { + return _fpsCap; +} + +void +Configuration::setFpsCap(float cap) { + _fpsCap = cap; + _conf.setValue("fps_cap", _fpsCap); + _conf.save(); +} + +bool +Configuration::cheatMode() const { + return _cheatMode; +} + +void +Configuration::setCheatMode(bool enabled) { + _cheatMode = enabled; + _conf.setValue("cheat_mode", _cheatMode); + _conf.save(); +} + +bool +Configuration::advancedMode() const { + return _advancedMode; +} + +void +Configuration::setAdvancedMode(bool enabled) { + _advancedMode = enabled; + _conf.setValue("advanced_mode", _advancedMode); + _conf.save(); +} + +bool +Configuration::checkUpdatesOnStartup() const { + return _checkUpdatesOnStartup; +} + +void +Configuration::setCheckUpdatesOnStartup(bool mode) { + _checkUpdatesOnStartup = mode; + _conf.setValue("startup_update_check", _checkUpdatesOnStartup); + _conf.save(); +} + +bool +Configuration::skipDisclaimer() const { + return _skipDisclaimer; +} + +void +Configuration::setSkipDisclaimer(bool mode) { + _skipDisclaimer = mode; + _conf.setValue("skip_disclaimer", _skipDisclaimer); + _conf.save(); +} + +Configuration& +Configuration::instance() { + static Configuration conf{}; + return conf; +} + +Configuration& +conf() { + return Configuration::instance(); +} diff --git a/src/Configuration/Configuration.h b/src/Configuration/Configuration.h new file mode 100644 index 0000000..c20cc5e --- /dev/null +++ b/src/Configuration/Configuration.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +using namespace Corrade; + +class Configuration { + public: + static Configuration& instance(); + + ~Configuration(); + + void save(); + + int swapInterval() const; + void setSwapInterval(int interval); + + float fpsCap() const; + void setFpsCap(float cap); + + bool cheatMode() const; + void setCheatMode(bool enabled); + + bool advancedMode() const; + void setAdvancedMode(bool enabled); + + bool checkUpdatesOnStartup() const; + void setCheckUpdatesOnStartup(bool mode); + + bool skipDisclaimer() const; + void setSkipDisclaimer(bool mode); + + private: + explicit Configuration(); + + Utility::Configuration _conf; + + int _swapInterval = 1; + float _fpsCap = 60.0f; + bool _cheatMode = false; + bool _advancedMode = false; + bool _checkUpdatesOnStartup = true; + bool _skipDisclaimer = false; +}; + +Configuration& conf(); diff --git a/src/SaveTool/SaveTool.cpp b/src/SaveTool/SaveTool.cpp index 4c6356c..a39d798 100644 --- a/src/SaveTool/SaveTool.cpp +++ b/src/SaveTool/SaveTool.cpp @@ -35,6 +35,7 @@ #include #include "../FontAwesome/IconsFontAwesome5.h" +#include "../Configuration/Configuration.h" #include "../Logger/Logger.h" using namespace Containers::Literals; @@ -130,7 +131,7 @@ SaveTool::SaveTool(const Arguments& arguments): LOG_INFO("Initialising update checker."); curl_global_init(CURL_GLOBAL_DEFAULT); - if(_checkUpdatesOnStartup) { + if(conf().checkUpdatesOnStartup()) { _queue.addToast(Toast::Type::Default, "Checking for updates..."_s); _updateThread = std::thread{[this]{ checkForUpdates(); }}; } @@ -141,7 +142,7 @@ SaveTool::SaveTool(const Arguments& arguments): GL::DebugOutput::setEnabled(GL::DebugOutput::Source::Api, GL::DebugOutput::Type::Other, {131185}, false); } - if(_skipDisclaimer) { + if(conf().skipDisclaimer()) { _uiState = UiState::Initialising; _initThread = std::thread{[this]{ initialiseManager(); }}; } @@ -159,14 +160,7 @@ SaveTool::~SaveTool() { LOG_INFO("Saving the configuration."); - _conf.setValue("cheat_mode"_s, _cheatMode); - _conf.setValue("advanced_mode"_s, _advancedMode); - _conf.setValue("startup_update_check"_s, _checkUpdatesOnStartup); - _conf.setValue("skip_disclaimer"_s, _skipDisclaimer); - _conf.setValue("swap_interval"_s, _swapInterval); - _conf.setValue("fps_cap"_s, _fpsCap); - - _conf.save(); + conf().save(); LOG_INFO("Exiting."); } @@ -182,8 +176,8 @@ void SaveTool::drawEvent() { swapBuffers(); - if(_swapInterval == 0 && _fpsCap < 301.0f) { - while(_timeline.currentFrameDuration() < (1.0f / _fpsCap)); + if(conf().swapInterval() == 0 && conf().fpsCap() < 301.0f) { + while(_timeline.currentFrameDuration() < (1.0f / conf().fpsCap())); } redraw(); @@ -344,7 +338,9 @@ void SaveTool::drawDisclaimer() { ImGui::Dummy({0.0f, 5.0f}); ImGui::Dummy({4.0f, 0.0f}); ImGui::SameLine(); - ImGui::Checkbox("Don't show next time", &_skipDisclaimer); + if(drawCheckbox("Don't show next time", conf().skipDisclaimer())) { + conf().setSkipDisclaimer(!conf().skipDisclaimer()); + } ImGui::TableSetColumnIndex(1); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {24.0f, 12.0f}); if(ImGui::Button("I understand the risks")) { diff --git a/src/SaveTool/SaveTool.h b/src/SaveTool/SaveTool.h index 6d21401..decc9c7 100644 --- a/src/SaveTool/SaveTool.h +++ b/src/SaveTool/SaveTool.h @@ -21,7 +21,6 @@ #include #include -#include #include #ifdef SAVETOOL_DEBUG_BUILD #include @@ -198,7 +197,6 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener void checkForUpdates(); - Utility::Configuration _conf{"MassBuilderSaveTool.ini"_s}; Utility::Resource _rs{"assets"_s}; // GUI-related members @@ -263,12 +261,6 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener }; Containers::StaticArray<2, efsw::WatchID> _watchIDs; - int _swapInterval = 1; - float _fpsCap = 60.0f; - - bool _skipDisclaimer{false}; - bool _checkUpdatesOnStartup{true}; - bool _updateAvailable{false}; Containers::String _latestVersion; Containers::String _releaseLink; @@ -291,8 +283,5 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener bool _bLaunchersDirty{false}; bool _eLaunchersDirty{false}; - bool _cheatMode{false}; - bool _advancedMode{false}; - Timeline _timeline; }; diff --git a/src/SaveTool/SaveTool_Initialisation.cpp b/src/SaveTool/SaveTool_Initialisation.cpp index 5f5ed49..ad1ec60 100644 --- a/src/SaveTool/SaveTool_Initialisation.cpp +++ b/src/SaveTool/SaveTool_Initialisation.cpp @@ -24,6 +24,7 @@ #include +#include "../Configuration/Configuration.h" #include "../FontAwesome/IconsFontAwesome5.h" #include "../FontAwesome/IconsFontAwesome5Brands.h" #include "../Logger/Logger.h" @@ -51,62 +52,8 @@ void SaveTool::initEvent(SDL_Event& event) { void SaveTool::initialiseConfiguration() { LOG_INFO("Reading configuration file."); - if(_conf.hasValue("cheat_mode"_s)) { - _cheatMode = _conf.value("cheat_mode"_s); - } - else { - _conf.setValue("cheat_mode"_s, _cheatMode); - } - - if(_conf.hasValue("advanced_mode"_s)) { - _advancedMode = _conf.value("advanced_mode"_s); - } - else { - _conf.setValue("advanced_mode"_s, _advancedMode); - } - - if(_conf.hasValue("startup_update_check"_s)) { - _checkUpdatesOnStartup = _conf.value("startup_update_check"_s); - } - else { - _conf.setValue("startup_update_check"_s, _checkUpdatesOnStartup); - } - - if(_conf.hasValue("skip_disclaimer"_s)) { - _skipDisclaimer = _conf.value("skip_disclaimer"_s); - } - else { - _conf.setValue("skip_disclaimer"_s, _skipDisclaimer); - } - - if(_conf.hasValue("swap_interval"_s)) { - _swapInterval = _conf.value("swap_interval"_s); - } - else { - _conf.setValue("swap_interval"_s, 1); - } - - if(_conf.hasValue("fps_cap"_s)) { - _fpsCap = _conf.value("fps_cap"); - } - else { - _conf.setValue("fps_cap", 60.0f); - } - - if(_conf.hasValue("frame_limit"_s)) { - std::string frame_limit = _conf.value("frame_limit"_s); - if(frame_limit == "half_vsync"_s) { - _swapInterval = 2; - } - _conf.removeValue("frame_limit"_s); - } - - setSwapInterval(_swapInterval); - if(_swapInterval == 0) { - setMinimalLoopPeriod(0); - } - - _conf.save(); + setSwapInterval(conf().swapInterval()); + setMinimalLoopPeriod(0); } void SaveTool::initialiseGui() { diff --git a/src/SaveTool/SaveTool_MainManager.cpp b/src/SaveTool/SaveTool_MainManager.cpp index 2f0d1c7..d8736d8 100644 --- a/src/SaveTool/SaveTool_MainManager.cpp +++ b/src/SaveTool/SaveTool_MainManager.cpp @@ -21,6 +21,7 @@ #include +#include "../Configuration/Configuration.h" #include "../FontAwesome/IconsFontAwesome5.h" #include "../Maps/LastMissionId.h" #include "../Maps/StoryProgress.h" @@ -224,7 +225,7 @@ void SaveTool::drawGeneralInfo() { } } - if(!_cheatMode) { + if(!conf().cheatMode()) { return; } @@ -403,7 +404,7 @@ void SaveTool::drawMaterialRow(Containers::StringView name, Int tier, Getter get ImGui::TableSetColumnIndex(2); if(getter() != -1) { ImGui::Text("%i", getter()); - if(_cheatMode) { + if(conf().cheatMode()) { ImGui::TableSetColumnIndex(3); ImGui::PushID(name.data()); static Int var = 0; diff --git a/src/SaveTool/SaveTool_MassViewer.cpp b/src/SaveTool/SaveTool_MassViewer.cpp index 7ff8c5f..5bc6e36 100644 --- a/src/SaveTool/SaveTool_MassViewer.cpp +++ b/src/SaveTool/SaveTool_MassViewer.cpp @@ -19,6 +19,7 @@ #include +#include "../Configuration/Configuration.h" #include "../FontAwesome/IconsFontAwesome5.h" #include "../Maps/Accessories.h" #define STYLENAMES_DEFINITION @@ -393,10 +394,10 @@ auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult { void SaveTool::drawDecalEditor(Decal& decal) { ImGui::Text("ID: %i", decal.id); - if(ImGui::BeginTable("##DecalTable", _advancedMode ? 2 : 1, ImGuiTableFlags_BordersInnerV)) { + if(ImGui::BeginTable("##DecalTable", conf().advancedMode() ? 2 : 1, ImGuiTableFlags_BordersInnerV)) { ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch); - if(_advancedMode) { + if(conf().advancedMode()) { ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch); } @@ -442,7 +443,7 @@ void SaveTool::drawDecalEditor(Decal& decal) { ImGui::Checkbox("##Wrap", &decal.wrap); ImGui::EndGroup(); - if(_advancedMode) { + if(conf().advancedMode()) { ImGui::TableNextColumn(); ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE); @@ -635,11 +636,11 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView +#include "../Configuration/Configuration.h" #include "../FontAwesome/IconsFontAwesome5.h" #include "../FontAwesome/IconsFontAwesome5Brands.h" #include "SaveTool.h" void SaveTool::drawMainMenu() { - if(ImGui::BeginMainMenuBar()) { - if(ImGui::BeginMenu("Save Tool##SaveToolMenu")) { - if(ImGui::BeginMenu(ICON_FA_FOLDER_OPEN " Open game data directory", Utility::Path::exists(_gameDataDir))) { - if(ImGui::MenuItem(ICON_FA_COG " Configuration", nullptr, false, Utility::Path::exists(_configDir))) { - openUri(Utility::Path::toNativeSeparators(_configDir)); - } + if(!ImGui::BeginMainMenuBar()) { + return; + } - if(ImGui::MenuItem(ICON_FA_SAVE " Saves", nullptr, false, Utility::Path::exists(_saveDir))) { - openUri(Utility::Path::toNativeSeparators(_saveDir)); - } - - if(ImGui::MenuItem(ICON_FA_IMAGE " Screenshots", nullptr, false, Utility::Path::exists(_screenshotsDir))) { - openUri(Utility::Path::toNativeSeparators(_screenshotsDir)); - } - - ImGui::EndMenu(); + if(ImGui::BeginMenu("Save Tool##SaveToolMenu")) { + if(ImGui::BeginMenu(ICON_FA_FOLDER_OPEN " Open game data directory", Utility::Path::exists(_gameDataDir))) { + if(ImGui::MenuItem(ICON_FA_COG " Configuration", nullptr, false, Utility::Path::exists(_configDir))) { + openUri(Utility::Path::toNativeSeparators(_configDir)); } - if(ImGui::BeginMenu(ICON_FA_FOLDER_OPEN " Open manager directory")) { - if(ImGui::MenuItem(ICON_FA_FILE_ARCHIVE " Profile backups", nullptr, false, Utility::Path::exists(_backupsDir))) { - openUri(Utility::Path::toNativeSeparators(_backupsDir)); - } - - if(ImGui::MenuItem(ICON_FA_EXCHANGE_ALT " Staging area", nullptr, false, Utility::Path::exists(_stagingDir))) { - openUri(Utility::Path::toNativeSeparators(_stagingDir)); - } - - ImGui::EndMenu(); + if(ImGui::MenuItem(ICON_FA_SAVE " Saves", nullptr, false, Utility::Path::exists(_saveDir))) { + openUri(Utility::Path::toNativeSeparators(_saveDir)); } - ImGui::Separator(); + if(ImGui::MenuItem(ICON_FA_IMAGE " Screenshots", nullptr, false, Utility::Path::exists(_screenshotsDir))) { + openUri(Utility::Path::toNativeSeparators(_screenshotsDir)); + } - if(ImGui::BeginMenu(ICON_FA_COG " Settings")) { - ImGui::BeginGroup(); - drawAlignedText("Vertical sync:"); - if(_swapInterval == 0) { - drawAlignedText("FPS cap:"); - } - ImGui::EndGroup(); + ImGui::EndMenu(); + } - ImGui::SameLine(); + if(ImGui::BeginMenu(ICON_FA_FOLDER_OPEN " Open manager directory")) { + if(ImGui::MenuItem(ICON_FA_FILE_ARCHIVE " Profile backups", nullptr, false, Utility::Path::exists(_backupsDir))) { + openUri(Utility::Path::toNativeSeparators(_backupsDir)); + } - ImGui::BeginGroup(); + if(ImGui::MenuItem(ICON_FA_EXCHANGE_ALT " Staging area", nullptr, false, Utility::Path::exists(_stagingDir))) { + openUri(Utility::Path::toNativeSeparators(_stagingDir)); + } - static const char* framelimit_labels[] = { - "Off", - "Every VBLANK", - "Every second VBLANK", - "Every third VBLANK", - }; + ImGui::EndMenu(); + } - ImGui::PushItemWidth(300.0f); + ImGui::Separator(); - if(ImGui::BeginCombo("##FrameLimit", framelimit_labels[_swapInterval])) { - for(int i = 0; i <= 3; i++) { - if(ImGui::Selectable(framelimit_labels[i], _swapInterval == i)) { - _swapInterval = i; - setSwapInterval(i); - if(i == 0) { - setMinimalLoopPeriod(0); - } + if(ImGui::BeginMenu(ICON_FA_COG " Settings")) { + ImGui::BeginGroup(); + drawAlignedText("Vertical sync:"); + if(conf().swapInterval() == 0) { + drawAlignedText("FPS cap:"); + } + ImGui::EndGroup(); + + ImGui::SameLine(); + + ImGui::BeginGroup(); + + static const char* framelimit_labels[] = { + "Off", + "Every VBLANK", + "Every second VBLANK", + "Every third VBLANK", + }; + + ImGui::PushItemWidth(300.0f); + + if(ImGui::BeginCombo("##FrameLimit", framelimit_labels[conf().swapInterval()])) { + for(int i = 0; i <= 3; i++) { + if(ImGui::Selectable(framelimit_labels[i], conf().swapInterval() == i)) { + conf().setSwapInterval(i); + setSwapInterval(i); + if(i == 0) { + setMinimalLoopPeriod(0); } } - - ImGui::EndCombo(); } - if(_swapInterval == 0) { - ImGui::SliderFloat("##FpsCapSlider", &_fpsCap, 15.0f, 301.0f, - _fpsCap != 301.0f ? "%.0f" : "Uncapped", ImGuiSliderFlags_AlwaysClamp); + ImGui::EndCombo(); + } + + if(conf().swapInterval() == 0) { + static float fps_cap = conf().fpsCap(); + if(ImGui::SliderFloat("##FpsCapSlider", &fps_cap, 15.0f, 301.0f, + conf().fpsCap() != 301.0f ? "%.0f" : "Uncapped", ImGuiSliderFlags_AlwaysClamp)) + { + conf().setFpsCap(fps_cap); } + } - ImGui::PopItemWidth(); + ImGui::PopItemWidth(); - ImGui::EndGroup(); + ImGui::EndGroup(); - ImGui::Checkbox("Cheat mode", &_cheatMode); + if(drawCheckbox("Cheat mode", conf().cheatMode())) { + conf().setCheatMode(!conf().cheatMode()); + } + ImGui::SameLine(); + ImGui::AlignTextToFramePadding(); + drawHelpMarker("This gives access to save edition features that can be considered cheats.", + Float(windowSize().x()) * 0.4f); + + if(drawCheckbox("Advanced mode", conf().advancedMode())) { + conf().setAdvancedMode(!conf().advancedMode()); + } + ImGui::SameLine(); + ImGui::AlignTextToFramePadding(); + drawHelpMarker("This gives access to editing values that have unknown purposes or are undocumented.", + Float(windowSize().x()) * 0.4f); + + if(drawCheckbox("Check for updates on startup", conf().checkUpdatesOnStartup())) { + conf().setCheckUpdatesOnStartup(!conf().checkUpdatesOnStartup()); + } + ImGui::SameLine(); + if(ImGui::Button(ICON_FA_SYNC_ALT " Check now")) { + _queue.addToast(Toast::Type::Default, "Checking for updates..."); + _updateThread = std::thread{[this]{ checkForUpdates(); }}; + } + + if(_updateAvailable) { + drawAlignedText("Version %s is available.", _latestVersion.data()); + if(ImGui::Button(ICON_FA_FILE_SIGNATURE " Release notes")) { + openUri(_releaseLink); + } ImGui::SameLine(); - ImGui::AlignTextToFramePadding(); - drawHelpMarker("This gives access to save edition features that can be considered cheats.", - Float(windowSize().x()) * 0.4f); - - ImGui::Checkbox("Advanced mode", &_advancedMode); - ImGui::SameLine(); - ImGui::AlignTextToFramePadding(); - drawHelpMarker("This gives access to editing values that have unknown purposes or are undocumented.", - 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..."); - _updateThread = std::thread{[this]{ checkForUpdates(); }}; + if(ImGui::Button(ICON_FA_DOWNLOAD " Download now")) { + openUri(_downloadLink); } - - if(_updateAvailable) { - drawAlignedText("Version %s is available.", _latestVersion.data()); - if(ImGui::Button(ICON_FA_FILE_SIGNATURE " Release notes")) { - openUri(_releaseLink); - } - ImGui::SameLine(); - if(ImGui::Button(ICON_FA_DOWNLOAD " Download now")) { - openUri(_downloadLink); - } - } - - ImGui::Checkbox("Skip disclaimer", &_skipDisclaimer); - - ImGui::EndMenu(); } - ImGui::Separator(); - - if(ImGui::MenuItem(ICON_FA_SIGN_OUT_ALT " Quit##QuitMenuItem")) { - exit(EXIT_SUCCESS); + if(drawCheckbox("Skip disclaimer", conf().skipDisclaimer())) { + conf().setSkipDisclaimer(!conf().skipDisclaimer()); } ImGui::EndMenu(); } - if(ImGui::BeginMenu("Game##GameMenu")) { - if(ImGui::MenuItem(ICON_FA_PLAY " Run demo##RunDemoMenuItem")) { - openUri("steam://run/1048390"); - } - drawTooltip("Will not work if you have the full game."); + ImGui::Separator(); - if(ImGui::MenuItem(ICON_FA_PLAY " Run full game##RunFullGameMenuItem")) { - openUri("steam://run/956680"); - } - - ImGui::Separator(); - - if(ImGui::BeginMenu(ICON_FA_DISCORD " Discord communities")) { - if(ImGui::MenuItem("Official server")) { - openUri("https://discord.gg/sekai-project"); - } - - if(ImGui::MenuItem("Community server")) { - openUri("https://discord.gg/massbuildercommunity"); - } - - ImGui::EndMenu(); - } - - ImGui::EndMenu(); + if(ImGui::MenuItem(ICON_FA_SIGN_OUT_ALT " Quit##QuitMenuItem")) { + exit(EXIT_SUCCESS); } - #ifdef SAVETOOL_DEBUG_BUILD - if(ImGui::BeginMenu("Debug tools")) { - ImGui::MenuItem("ImGui demo window", nullptr, &_demoWindow); - ImGui::MenuItem("ImGui style editor", nullptr, &_styleEditor); - ImGui::MenuItem("ImGui metrics window", nullptr, &_metricsWindow); - - ImGui::EndMenu(); - } - #endif - - if(ImGui::BeginMenu("Help")) { - if(ImGui::BeginMenu(ICON_FA_KEYBOARD " Keyboard shortcuts")) { - ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); - ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); - ImGui::BulletText("While inputing text:\n"); - ImGui::Indent(); - ImGui::BulletText("CTRL+Left/Right to word jump."); - ImGui::BulletText("CTRL+A or double-click to select all."); - ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); - ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); - ImGui::BulletText("ESCAPE to revert."); - ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); - ImGui::Unindent(); - ImGui::EndMenu(); - } - ImGui::MenuItem(ICON_FA_INFO_CIRCLE " About", nullptr, &_aboutPopup); - - ImGui::EndMenu(); - } - - if(_gameCheckTimerId != 0) { - if(ImGui::BeginTable("##MainMenuLayout", 2)) { - ImGui::TableSetupColumn("##Dummy", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("##GameState", ImGuiTableColumnFlags_WidthFixed); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(1); - drawGameState(); - - ImGui::EndTable(); - } - } - - ImGui::EndMainMenuBar(); + ImGui::EndMenu(); } + + if(ImGui::BeginMenu("Game##GameMenu")) { + if(ImGui::MenuItem(ICON_FA_PLAY " Run demo##RunDemoMenuItem")) { + openUri("steam://run/1048390"); + } + drawTooltip("Will not work if you have the full game."); + + if(ImGui::MenuItem(ICON_FA_PLAY " Run full game##RunFullGameMenuItem")) { + openUri("steam://run/956680"); + } + + ImGui::Separator(); + + if(ImGui::BeginMenu(ICON_FA_DISCORD " Discord communities")) { + if(ImGui::MenuItem("Official server")) { + openUri("https://discord.gg/sekai-project"); + } + + if(ImGui::MenuItem("Community server")) { + openUri("https://discord.gg/massbuildercommunity"); + } + + ImGui::EndMenu(); + } + + ImGui::EndMenu(); + } + + #ifdef SAVETOOL_DEBUG_BUILD + if(ImGui::BeginMenu("Debug tools")) { + ImGui::MenuItem("ImGui demo window", nullptr, &_demoWindow); + ImGui::MenuItem("ImGui style editor", nullptr, &_styleEditor); + ImGui::MenuItem("ImGui metrics window", nullptr, &_metricsWindow); + + ImGui::EndMenu(); + } + #endif + + if(ImGui::BeginMenu("Help")) { + if(ImGui::BeginMenu(ICON_FA_KEYBOARD " Keyboard shortcuts")) { + ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); + ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); + ImGui::BulletText("While inputing text:\n"); + ImGui::Indent(); + ImGui::BulletText("CTRL+Left/Right to word jump."); + ImGui::BulletText("CTRL+A or double-click to select all."); + ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); + ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); + ImGui::BulletText("ESCAPE to revert."); + ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); + ImGui::Unindent(); + ImGui::EndMenu(); + } + ImGui::MenuItem(ICON_FA_INFO_CIRCLE " About", nullptr, &_aboutPopup); + + ImGui::EndMenu(); + } + + if(_gameCheckTimerId != 0) { + if(ImGui::BeginTable("##MainMenuLayout", 2)) { + ImGui::TableSetupColumn("##Dummy", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("##GameState", ImGuiTableColumnFlags_WidthFixed); + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(1); + drawGameState(); + + ImGui::EndTable(); + } + } + + ImGui::EndMainMenuBar(); }