diff --git a/include/store/store.hpp b/include/store/store.hpp index b27bfb5..e7f4ba6 100644 --- a/include/store/store.hpp +++ b/include/store/store.hpp @@ -33,7 +33,7 @@ class Store { public: - Store(const std::string &file); + Store(const std::string &file, const std::string &file2, bool ARGMode = false); ~Store(); void LoadFromFile(const std::string &file); void loadSheets(); @@ -80,6 +80,9 @@ public: /* Both of these things are used for custom BG support. */ C2D_Image GetStoreImg() const { return this->storeBG; }; bool customBG() const { return this->hasCustomBG; }; + + /* Return filename of the UniStore. */ + std::string GetFileName() const { return this->fileName; }; private: void SetC2DBGImage(); nlohmann::json storeJson = nullptr; @@ -87,6 +90,7 @@ private: C2D_Image storeBG = { nullptr }; bool valid = false, hasSheet = false, hasCustomBG = false; int screenIndex = 0, entry = 0, box = 0, downEntry = 0, downIndex = 0; + std::string fileName = ""; }; #endif \ No newline at end of file diff --git a/include/utils/argumentParser.hpp b/include/utils/argumentParser.hpp new file mode 100644 index 0000000..eb2f9c3 --- /dev/null +++ b/include/utils/argumentParser.hpp @@ -0,0 +1,47 @@ +/* +* This file is part of Universal-Updater +* Copyright (C) 2019-2020 Universal-Team +* +* 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 . +* +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. +*/ + +#ifndef _UNIVERSAL_UPDATER_ARGUMENT_PARSER_HPP +#define _UNIVERSAL_UPDATER_ARGUMENT_PARSER_HPP + +#include "json.hpp" +#include "store.hpp" +#include + +class ArgumentParser { +public: + ArgumentParser(const std::string &file, const std::string &entry, int dlIndex); + void Load(); + void Execute(); + bool GetValid() const { return this->isValid; }; +private: + std::unique_ptr store = nullptr; + bool isValid = false; + std::string file = "", executeEntry = "", entry = ""; + int dlIndex = -1, entryIndex = -1; +}; + +#endif \ No newline at end of file diff --git a/include/utils/config.hpp b/include/utils/config.hpp index 51d9ff8..0014304 100644 --- a/include/utils/config.hpp +++ b/include/utils/config.hpp @@ -79,6 +79,10 @@ public: /* If using custom Font. */ bool customfont() const { return this->v_customFont; }; void customfont(bool v) { this->v_customFont = v; if (!this->changesMade) this->changesMade = true; }; + + /* The shortcut path. */ + std::string shortcut() const { return this->v_shortcutPath; }; + void shortcut(const std::string &v) { this->v_shortcutPath = v; if (!this->changesMade) this->changesMade = true; }; private: /* Mainly helper. */ bool getBool(const std::string &key); @@ -92,7 +96,8 @@ private: bool changesMade = false; std::string v_language = "en", v_lastStore = "universal-db.unistore", - v_3dsxPath = "sdmc:/3ds", v_ndsPath = "sdmc:", v_archivePath = "sdmc:"; + v_3dsxPath = "sdmc:/3ds", v_ndsPath = "sdmc:", v_archivePath = "sdmc:", + v_shortcutPath = "sdmc:/3ds/Universal-Updater/shortcuts"; bool v_list = false, v_autoUpdate = true, v_metadata = true, v_updateCheck = true, v_showBg = false, v_customFont = false; }; diff --git a/romfs/lang/en/app.json b/romfs/lang/en/app.json index d212528..20c0030 100644 --- a/romfs/lang/en/app.json +++ b/romfs/lang/en/app.json @@ -1,5 +1,6 @@ { "ASCENDING": "Ascending", + "ARGUMENT_INVALID": "Argument invalid.\nPlease check the xml file for proper arguments.", "AUTHOR": "Author", "AUTO_UPDATE_SETTINGS": "Auto-Update Settings", "AUTO_UPDATE_SETTINGS_BTN": "Auto-update settings...", @@ -13,6 +14,7 @@ "CHANGE_3DSX_PATH": "Change 3DSX path", "CHANGE_ARCHIVE_PATH": "Change archive path", "CHANGE_NDS_PATH": "Change NDS path", + "CHANGE_SHORTCUT_PATH": "Change shortcut path", "CHECK_UNISTORE_UPDATES": "Checking for UniStore updates...", "CHECK_UU_UPDATES": "Checking for Universal-Updater updates...", "CONFIRM_OR_CANCEL": "Press \uE000 to confirm, \uE001 to cancel.", @@ -20,6 +22,7 @@ "CONSOLE": "Console", "CONTRIBUTOR_TRANSLATORS": "- All Translators & Contributors", "COPY_ERROR": "Copy Error!", + "CREATE_SHORTCUT": "Would you like to create a shortcut?", "CREDITS": "Credits", "CURRENT_VERSION": "Current version: ", "CURRENTLY_EXTRACTING": "Currently extracting:\n", @@ -45,7 +48,10 @@ "DOWNLOADING_UNISTORE": "Downloading UniStore...", "ENABLE_AUTOUPDATE_UNISTORE": "Enable auto-update UniStore on boot", "ENABLE_UPDATE_CHECK": "Enable self-updating", + "ENTER_DESC_SHORTCUT": "Enter the shortcut description.", "ENTER_SEARCH": "Enter what you like to search.", + "ENTER_SHORTCUT_FILENAME": "Enter the shortcut filename (without extension).", + "ENTER_TITLE_SHORTCUT": "Enter the shortcut title.", "ENTER_URL": "Enter the URL of the UniStore.", "ENTRIES": "Entries", "EXECUTE_ENTRY": "Would you like to execute this entry?", @@ -83,6 +89,7 @@ "SELECT_UNISTORE_2": "Select a UniStore", "SETTINGS": "Settings", "SHEET_SLASH": "Seems like a '/' is included, which is not supported.\nPlease change 'sheet' to filename only.", + "SHORTCUT_CREATED": "Shortcut created!", "SORT_BY": "Sort By", "SORTING": "Sorting", "START_SELECT": "Press START to select the current folder", diff --git a/source/gui/msg.cpp b/source/gui/msg.cpp index d3fcc4a..9b1e5f3 100644 --- a/source/gui/msg.cpp +++ b/source/gui/msg.cpp @@ -75,6 +75,7 @@ bool Msg::promptMsg(const std::string &promptMsg) { Gui::clearTextBufs(); C3D_FrameBegin(C3D_FRAME_SYNCDRAW); C2D_TargetClear(Top, TRANSPARENT); + C2D_TargetClear(Bottom, TRANSPARENT); GFX::DrawTop(); Gui::Draw_Rect(0, 215, 400, 25, BAR_COLOR); @@ -82,6 +83,7 @@ bool Msg::promptMsg(const std::string &promptMsg) { Gui::DrawStringCentered(0, (240 - Gui::GetStringHeight(0.6f, promptMsg)) / 2, 0.6f, TEXT_COLOR, promptMsg, 395, 0, font); Gui::DrawStringCentered(0, 218, 0.6f, TEXT_COLOR, Lang::get("CONFIRM_OR_CANCEL"), 390, 0, font); + GFX::DrawBottom(); C3D_FrameEnd(0); for (int i = 0; i < 3; i++) gspWaitForVBlank(); diff --git a/source/init.cpp b/source/init.cpp index 295ad6b..49841a2 100644 --- a/source/init.cpp +++ b/source/init.cpp @@ -103,6 +103,7 @@ Result Init::Initialize() { mkdir("sdmc:/3ds", 0777); mkdir("sdmc:/3ds/Universal-Updater", 0777); mkdir("sdmc:/3ds/Universal-Updater/stores", 0777); + mkdir("sdmc:/3ds/Universal-Updater/shortcuts", 0777); config = std::make_unique(); Lang::load(config->language()); diff --git a/source/keyboard.cpp b/source/keyboard.cpp index ea234cf..7eefc59 100644 --- a/source/keyboard.cpp +++ b/source/keyboard.cpp @@ -62,7 +62,7 @@ std::string Input::setkbdString(uint maxLength, const std::string &Text, const s } } - SwkbdButton ret = swkbdInputText(&state, temp, maxLength); + SwkbdButton ret = swkbdInputText(&state, temp, sizeof(temp)); temp[maxLength] = '\0'; return (ret == SWKBD_BUTTON_CONFIRM ? temp : ""); diff --git a/source/main.cpp b/source/main.cpp index 5c500ff..be81717 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -24,13 +24,69 @@ * reasonable ways as different from the original version. */ +#include "argumentParser.hpp" +#include "common.hpp" #include "init.hpp" +#include #include +#define ARG_AMOUNT 4 // In case for more args, change this. It must be ARG amount + 1, because of 3DSX Path. std::string _3dsxPath = ""; +/* + ARG Init. +*/ +static void InitForARG() { + gfxInitDefault(); + romfsInit(); + Gui::init(); + amInit(); + acInit(); + + /* Create Directories, if missing. */ + mkdir("sdmc:/3ds", 0777); + mkdir("sdmc:/3ds/Universal-Updater", 0777); + mkdir("sdmc:/3ds/Universal-Updater/stores", 0777); + mkdir("sdmc:/3ds/Universal-Updater/shortcuts", 0777); + + config = std::make_unique(); + Lang::load(config->language()); + Init::LoadFont(); + osSetSpeedupEnable(true); // Enable speed-up for New 3DS users. +} + +/* + ARG Exit. +*/ +static Result ExitForARG() { + Gui::exit(); + Init::UnloadFont(); + gfxExit(); + cfguExit(); + acExit(); + amExit(); + romfsExit(); + + return 0; +} + int main(int argc, char *argv[]) { if (argc > 0) _3dsxPath = argv[0]; + /* 4 --> Argument mode. */ + if (argc == ARG_AMOUNT) { + InitForARG(); + + const std::string file = argv[1]; + const std::string entry = argv[2]; + int dlIndex = atoi(argv[3]); + + std::unique_ptr arg = std::make_unique(file, entry, dlIndex); + + if (arg->GetValid()) arg->Execute(); // Execute, if valid. + else Msg::waitMsg(Lang::get("ARGUMENT_INVALID")); + return ExitForARG(); + } + return Init::MainLoop(); } \ No newline at end of file diff --git a/source/overlays/storeSelect.cpp b/source/overlays/storeSelect.cpp index 3df971a..ede803d 100644 --- a/source/overlays/storeSelect.cpp +++ b/source/overlays/storeSelect.cpp @@ -318,7 +318,7 @@ void Overlays::SelectStore(std::unique_ptr &store, std::vector 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW")); else { - store = std::make_unique(_STORE_PATH + info[selection].FileName); + store = std::make_unique(_STORE_PATH + info[selection].FileName, info[selection].FileName); StoreUtils::ResetAll(store, meta, entries); config->lastStore(info[selection].FileName); StoreUtils::SortEntries(false, SortType::LAST_UPDATED, entries); @@ -340,7 +340,7 @@ void Overlays::SelectStore(std::unique_ptr &store, std::vector 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW")); else { - store = std::make_unique(_STORE_PATH + info[i + sPos].FileName); + store = std::make_unique(_STORE_PATH + info[i + sPos].FileName, info[i + sPos].FileName); StoreUtils::ResetAll(store, meta, entries); config->lastStore(info[i + sPos].FileName); doOut = true; diff --git a/source/screens/mainScreen.cpp b/source/screens/mainScreen.cpp index 355c79d..6a612d2 100644 --- a/source/screens/mainScreen.cpp +++ b/source/screens/mainScreen.cpp @@ -94,7 +94,7 @@ MainScreen::MainScreen() { } } - this->store = std::make_unique(_STORE_PATH + config->lastStore()); + this->store = std::make_unique(_STORE_PATH + config->lastStore(), config->lastStore()); StoreUtils::ResetAll(this->store, this->meta, this->entries); StoreUtils::SortEntries(false, SortType::LAST_UPDATED, this->entries); }; diff --git a/source/store/downList.cpp b/source/store/downList.cpp index 081a14a..da29184 100644 --- a/source/store/downList.cpp +++ b/source/store/downList.cpp @@ -24,11 +24,15 @@ * reasonable ways as different from the original version. */ +#include "keyboard.hpp" #include "scriptUtils.hpp" #include "storeUtils.hpp" #include "structs.hpp" +#include #define DOWNLOAD_ENTRIES 7 +extern std::string _3dsxPath; +extern bool is3DSX; extern bool touching(touchPosition touch, Structs::ButtonPos button); static const std::vector downloadBoxes = { { 54, 32, 262, 22 }, @@ -40,6 +44,45 @@ static const std::vector downloadBoxes = { { 54, 212, 262, 22 } }; +/* + With this, we can create a shortcut. ;P + + const std::string &entryName: The name of the Entry. AKA: The Title Name. + int index: The Download index. + const std::string &unistoreName: The name of the UniStore filename. + const std::string &author: The author of the app. +*/ +static void CreateShortcut(const std::string &entryName, int index, const std::string &unistoreName, const std::string &author) { + std::string sName = Input::setkbdString(30, Lang::get("ENTER_SHORTCUT_FILENAME"), {}); + if (sName == "") sName = "tmp"; + std::ofstream out(config->shortcut() + "/" + sName + ".xml", std::ios::binary); + + out << "" << std::endl; + + /* Executable. */ + const std::string executable = _3dsxPath.substr(5, _3dsxPath.size()); // It must be '/3ds/...'. + out << " " << executable << "" << std::endl; + + /* Arguments. */ + out << " \"" << unistoreName << "\" \"" << entryName << "\" \"" << std::to_string(index) << "\"" << "" << std::endl; + + /* Title. */ + const std::string title = Input::setkbdString(30, Lang::get("ENTER_TITLE_SHORTCUT"), {}); + if (title != "") out << " " << title << "" << std::endl; + else out << " " << entryName << "" << std::endl; + + /* Description. */ + const std::string desc = Input::setkbdString(50, Lang::get("ENTER_DESC_SHORTCUT"), {}); + if (desc != "") out << " " << desc << "" << std::endl; + else out << " " << entryName << "" << std::endl; + + /* Author and end. */ + out << " " << author << "" << std::endl; + out << "" << std::endl; + out.close(); +} + + /* Draw the Download Entries part. @@ -87,6 +130,15 @@ void StoreUtils::DownloadHandle(const std::unique_ptr &store, const std:: smallDelay--; } + if ((hDown & KEY_Y) || (hDown & KEY_START)) { + if (is3DSX) { // Only allow if 3DSX. + if (Msg::promptMsg(Lang::get("CREATE_SHORTCUT"))) { + CreateShortcut(entry->GetTitle(), store->GetDownloadIndex(), store->GetFileName(), entry->GetAuthor()); + Msg::waitMsg(Lang::get("SHORTCUT_CREATED")); + } + } + } + if (hRepeat & KEY_DOWN) { if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid. @@ -122,9 +174,7 @@ void StoreUtils::DownloadHandle(const std::unique_ptr &store, const std:: for (int i = 0; i < DOWNLOAD_ENTRIES; i++) { if (touching(touch, downloadBoxes[i])) { if (i + store->GetDownloadSIndex() < (int)entries.size()) { - const std::string tmp = Lang::get("EXECUTE_ENTRY") + "\n\n" + entries[i + store->GetDownloadSIndex()]; - - if (Msg::promptMsg(tmp)) { + if (Msg::promptMsg(Lang::get("EXECUTE_ENTRY") + "\n\n" + entries[i + store->GetDownloadSIndex()])) { ScriptUtils::runFunctions(store->GetJson(), entry->GetEntryIndex(), entries[i + store->GetDownloadSIndex()]); if (meta) meta->SetUpdated(store->GetUniStoreTitle(), entry->GetTitle(), entry->GetLastUpdated()); entry->SetUpdateAvl(false); @@ -137,8 +187,7 @@ void StoreUtils::DownloadHandle(const std::unique_ptr &store, const std:: if (smallDelay == 0 && hDown & KEY_A) { if (entries.size() <= 0) return; // Smaller *than* 0 -> Invalid. - const std::string tmp = Lang::get("EXECUTE_ENTRY") + "\n\n" + entries[store->GetDownloadIndex()]; - if (Msg::promptMsg(tmp)) { + if (Msg::promptMsg(Lang::get("EXECUTE_ENTRY") + "\n\n" + entries[store->GetDownloadIndex()])) { ScriptUtils::runFunctions(store->GetJson(), entry->GetEntryIndex(), entries[store->GetDownloadIndex()]); if (meta) meta->SetUpdated(store->GetUniStoreTitle(), entry->GetTitle(), entry->GetLastUpdated()); entry->SetUpdateAvl(false); diff --git a/source/store/settings.cpp b/source/store/settings.cpp index 8b2feb3..3d4149f 100644 --- a/source/store/settings.cpp +++ b/source/store/settings.cpp @@ -63,7 +63,7 @@ static const Structs::ButtonPos back = { 52, 0, 24, 24 }; // Back arrow for dire static const std::vector mainStrings = { "LANGUAGE", "SELECT_UNISTORE", "AUTO_UPDATE_SETTINGS_BTN", "GUI_SETTINGS_BTN", "DIRECTORY_SETTINGS_BTN", "CREDITS", "EXIT_APP" }; -static const std::vector dirStrings = { "CHANGE_3DSX_PATH", "CHANGE_NDS_PATH", "CHANGE_ARCHIVE_PATH" }; +static const std::vector dirStrings = { "CHANGE_3DSX_PATH", "CHANGE_NDS_PATH", "CHANGE_ARCHIVE_PATH", "CHANGE_SHORTCUT_PATH" }; /* Note: Украïнська is spelled using a latin i with dieresis to work in the system font */ static const std::vector languages = { "Bruh", "Dansk", "Deutsch", "English", "Español", "Français", "Italiano", "Lietuvių", "Magyar", "Polski", "Português", "Português (Brasil)", "Русский", "Украïнська", "日本語" }; @@ -115,7 +115,7 @@ static void DrawSettingsDir(int selection) { GFX::DrawSprite(sprites_arrow_idx, back.x, back.y); Gui::DrawStringCentered(32, 2, 0.6, TEXT_COLOR, Lang::get("DIRECTORY_SETTINGS"), 240, 0, font); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 4; i++) { if (i == selection) GFX::DrawBox(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, false); Gui::DrawStringCentered(30, mainButtons[i].y + 4, 0.45f, TEXT_COLOR, Lang::get(dirStrings[i]), 255, 0, font); } @@ -293,18 +293,18 @@ static void SettingsHandleDir(int &page, int &selection, const std::unique_ptr 0) selection--; - else selection = dirStrings.size()-1; + else selection = dirStrings.size() - 1; } if (hRepeat & KEY_RIGHT) { - if (selection + 8 < (int)dirStrings.size()-1) selection += 8; - else selection = dirStrings.size()-1; + if (selection + 8 < (int)dirStrings.size() - 1) selection += 8; + else selection = dirStrings.size() - 1; } if (hRepeat & KEY_LEFT) { @@ -328,6 +328,10 @@ static void SettingsHandleDir(int &page, int &selection, const std::unique_ptrarchPath(), Lang::get("SELECT_DIR"), store); if (path != "") config->archPath(path); + + } else if (touching(touch, mainButtons[3])) { + const std::string path = Overlays::SelectDir(config->shortcut(), Lang::get("SELECT_DIR"), store); + if (path != "") config->shortcut(path); } } @@ -349,6 +353,11 @@ static void SettingsHandleDir(int &page, int &selection, const std::unique_ptrarchPath(), Lang::get("SELECT_DIR"), store); if (path != "") config->archPath(path); break; + + case 3: + path = Overlays::SelectDir(config->shortcut(), Lang::get("SELECT_DIR"), store); + if (path != "") config->shortcut(path); + break; } } } diff --git a/source/store/store.cpp b/source/store/store.cpp index 5038e5f..7eeb50e 100644 --- a/source/store/store.cpp +++ b/source/store/store.cpp @@ -39,10 +39,19 @@ static bool firstStart = true; Initialize a store. const std::string &file: The UniStore file. + const std::string &file2: The UniStore file.. without full path. + bool ARGMode: If Argument mode. */ -Store::Store(const std::string &file) { - this->update(file); - this->SetC2DBGImage(); +Store::Store(const std::string &file, const std::string &file2, bool ARGMode) { + this->fileName = file2; + + if (!ARGMode) { + this->update(file); + this->SetC2DBGImage(); + + } else { + this->LoadFromFile(file); + } }; /* diff --git a/source/utils/argumentParser.cpp b/source/utils/argumentParser.cpp new file mode 100644 index 0000000..29e165e --- /dev/null +++ b/source/utils/argumentParser.cpp @@ -0,0 +1,83 @@ +/* +* This file is part of Universal-Updater +* Copyright (C) 2019-2020 Universal-Team +* +* 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 . +* +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. +*/ + +#include "argumentParser.hpp" +#include "common.hpp" +#include "scriptUtils.hpp" +#include + +/* + The constructor of the Argument Parser. + + const std::string &file: Const Reference to the file. + const std::string &entry: Const Reference to the Entry Title name. + int dlIndex: The Download index. +*/ +ArgumentParser::ArgumentParser(const std::string &file, const std::string &entry, int dlIndex) { + if (dlIndex != -1 || file != "") { + this->file = file; + this->entry = entry; + this->dlIndex = dlIndex; + + this->Load(); + } +} + +/* + Prepare UniStore and get valid state. +*/ +void ArgumentParser::Load() { + if (access((std::string(_STORE_PATH) + this->file).c_str(), F_OK) != 0) return; + + this->store = std::make_unique(_STORE_PATH + this->file, this->file, true); + if (!this->store->GetValid()) return; + + for (int i = 0; i < this->store->GetStoreSize(); i++) { + if (this->store->GetTitleEntry(i) == this->entry) { + this->entryIndex = i; + const std::vector dlList = this->store->GetDownloadList(this->entryIndex); + + if (dlList.empty()) return; + + if ((int)dlList.size() >= this->dlIndex) { + this->executeEntry = dlList[this->dlIndex]; + this->isValid = true; + return; + } + } + } +} + +/* + Execute the Argument's entry, if valid. +*/ +void ArgumentParser::Execute() { + if (this->isValid) { + if (Msg::promptMsg(Lang::get("EXECUTE_ENTRY") + "\n\n" + this->executeEntry)) { + ScriptUtils::runFunctions(this->store->GetJson(), this->entryIndex, this->executeEntry); + } + } +} \ No newline at end of file diff --git a/source/utils/config.cpp b/source/utils/config.cpp index 6e3a7e1..ca8e867 100644 --- a/source/utils/config.cpp +++ b/source/utils/config.cpp @@ -124,6 +124,7 @@ Config::Config() { if (this->json.contains("UpdateCheck")) this->updatecheck(this->getBool("UpdateCheck")); if (this->json.contains("UseBG")) this->usebg(this->getBool("UseBG")); if (this->json.contains("CustomFont")) this->customfont(this->getBool("CustomFont")); + if (this->json.contains("Shortcut_Path")) this->shortcut(this->getString("Shortcut_Path")); this->changesMade = false; // No changes made yet. } @@ -146,6 +147,7 @@ void Config::save() { this->setBool("UpdateCheck", this->updatecheck()); this->setBool("UseBG", this->usebg()); this->setBool("CustomFont", this->customfont()); + this->setString("Shortcut_Path", this->shortcut()); /* Write changes to file. */ const std::string dump = this->json.dump(1, '\t');