Update readme, add legacy config loading, new translation format, remove curUser and curData definition shortcuts

This commit is contained in:
J-D-K 2021-08-16 21:58:18 -04:00
parent b74349f7c0
commit 2b6f91e20f
22 changed files with 927 additions and 711 deletions

View File

@ -38,7 +38,7 @@ INCLUDES := inc inc/ui
EXEFS_SRC := exefs_src
APP_TITLE := JKSV
APP_AUTHOR := JK
APP_VERSION := 08.04.2021
APP_VERSION := 08.16.2021
ROMFS := romfs
ICON := icon.jpg

View File

@ -80,8 +80,7 @@ JKSV on Switch started as a small project/port to test some things and get famil
2. Requires switch-freetype, libpng, zlib, libjpeg-turbo, lib-curl, and lib-json-c
## Credits and Thanks:
* [shared-font](https://github.com/switchbrew/switch-portlibs-examples) example by yellows8
* Authors of switch-examples for account and save mounting code.
* [shared-font](https://github.com/switchbrew/switch-portlibs-examples) example by yellows8 for loading system font with Freetype. All other font handling code (converting to SDL2, resizing on the fly, checking for glyphs, cache, etc) is my own.
* [Iguniisu](https://github.com/igniscitrinus) for the icon.
* Uses graphics from [Twemoji](https://github.com/twitter/twemoji) covered by the [Creative Commons License](https://creativecommons.org/licenses/by/4.0/legalcode)
* [Leo](https://github.com/qazrfv1234) For the Traditional Chinese translation

View File

@ -7,11 +7,8 @@
#include "gfx.h"
#define curUser users[data::selUser]
#define curData users[data::selUser].titleInfo[data::selData]
#define BLD_MON 8
#define BLD_DAY 4
#define BLD_DAY 16
#define BLD_YEAR 2021
namespace data
@ -86,7 +83,16 @@ namespace data
//Title data/info map
extern std::unordered_map<uint64_t, data::titleInfo> titles;
//Gets pointer to info
//Sets/Retrieves current user/title
void setUserIndex(unsigned _sUser);
data::user *getCurrentUser();
unsigned getCurrentUserIndex();
void setTitleIndex(unsigned _sTitle);
data::userTitleInfo *getCurrentUserTitleInfo();
unsigned getCurrentUserTitleInfoIndex();
//Gets pointer to info that also has title + nacp
data::titleInfo *getTitleInfoByTID(const uint64_t& tid);
//More shortcut functions
@ -102,6 +108,5 @@ namespace data
}
return -1;
}
extern int selUser, selData;
extern SetLanguage sysLang;
}

View File

@ -24,6 +24,7 @@ namespace fs
bool mountSave(const FsSaveDataInfo& _m);
inline bool unmountSave() { return fsdevUnmountDevice("sv") == 0; }
bool commitToDevice(const std::string& dev);
void createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _userID);
void copyFile(const std::string& from, const std::string& to);
void copyFileCommit(const std::string& from, const std::string& to, const std::string& dev);
@ -114,6 +115,7 @@ namespace fs
public:
dataFile(const std::string& _path);
~dataFile();
void close(){ fclose(f); }
bool isOpen() const { return opened; }
@ -154,6 +156,14 @@ namespace fs
void argUnlock() { mutexUnlock(&arglck); }
} copyArgs;
typedef struct
{
FsSaveDataType type;
uint64_t tid;
AccountUid account;
uint16_t index;
} svCreateArgs;
copyArgs *copyArgsCreate(const std::string& from, const std::string& to, const std::string& dev, zipFile z, unzFile unz, bool _cleanup);
void copyArgsDestroy(copyArgs *c);

View File

@ -6,6 +6,7 @@
namespace fs
{
void _fileDrawFunc(void *a);
void createSaveData_t(void *a);
void copyFile_t(void *a);
void copyFileCommit_t(void *a);
void copyDirToDir_t(void *a);

View File

@ -6,25 +6,16 @@
//Misc stuff for new menu code
typedef void (*funcPtr)(void *);
typedef struct
class threadStatus
{
Mutex statusLock = 0;
std::string status;
void setStatus(const std::string& newStatus)
{
mutexLock(&statusLock);
status = newStatus;
mutexUnlock(&statusLock);
}
public:
void setStatus(const char *fmt, ...);
void getStatus(std::string& statusOut);
void getStatus(std::string& statusOut)
{
mutexLock(&statusLock);
statusOut = status;
mutexUnlock(&statusLock);
}
} threadStatus;
private:
Mutex statusLock = 0;
std::string status;
};
typedef struct
{

View File

@ -1,28 +1,15 @@
#pragma once
#include <map>
//Strings since translation support
namespace ui
{
void initStrings();
void loadTrans();
void saveTranslationFile(void *a);
extern std::map<std::pair<std::string, int>, std::string> strings;
extern std::string author, userHelp, titleHelp, folderHelp, optHelp, \
confBlacklist, confOverwrite, confRestore, confDel, confCopy, \
confEraseNand, confEraseFolder, yt, nt, on, off, confirmHead, \
copyHead, noSavesFound, errorConnecting, noUpdate, saveCreated, saveCreateFailed, \
saveDataReset, saveDataResetSuccess, saveDataDeleteSuccess;
//Strings for file mode menu
extern std::string advMenuStr[7];
//Strings for extras menu
extern std::string exMenuStr[11];
//Strings for options menu
extern std::string optMenuStr[18];
//Strings for the holding thing
extern std::string holdingText[3];
//Strings for sort type
extern std::string sortString[3];
//Strings for user options
extern std::string usrOptString[2];
//Strings for title options
extern std::string titleOptString[7];
inline std::string getUIString(const std::string& _name, int ind){ return strings[std::make_pair(_name, ind)]; }
inline const char *getUICString(const std::string& _name, int ind){ return strings[std::make_pair(_name, ind)].c_str(); }
}

View File

@ -1,133 +1,114 @@
#JKSV Switch translation guide
#Button strings [X] are replaced by JKSV at boot.
#string = set string to this.
#Translation author. Displayed in UI. NULL is ignored and not displayed.
author = "NULL"
#JKSV Translation File
#File can be placed and named "/JKSV/trans.txt" for testing without building
#Format is: stringName = index, "string"
#You only need to translate "string", there is no need to touch the other two parameters.
#'%s' is replaced with game titles and paths. '#', '*', '>', etc change text color. [x] are replaced with button glyphs
#This is exported from JKSV itself to make adding strings to this easier.
#It can also export already made translations with new strings if added, cutting down work for everyone.
#If there are issues with spacing, line breaking, untranslatable English text, etc let me know in a git issue or your pull request.
#Help/Guide strings on bottom
#User Select
userHelp = "[A] Select [Y] Dump All [X] UI Mode [R] Update [-] Options [ZR] Extras"
#Title Select
titleHelp = "[A] Select [L][R] Change User [Y] Dump All [X] Favorite [-] BlackList [ZR] Erase [B] Back"
#Folder Select
folderHelp = "[-] File Mode [L]/[R]+[A] Auto [A] Backup [Y] Restore [X] Delete Selected [ZR] Erase [B] Back"
#Options Menu
optHelp = "[A] Toggle [X] Defaults [B] Back"
#Button prompts.
yt = "Yes [A]"
nt = "No [B]"
#On/Off for options. '>' is used to change color to green.
on = ">On>"
off = "Off"
#Strings for messages/confirmation. '*' and '#' are used in strings to change color. %s is replaced with titles and names with sprintf.
#Text shown at the top of confirmation boxes
confirmHead = "Confirm"
#Text shown at top of progress dialog when copying files
copyHead = "Copying File..."
#Confirm blacklist.
confirmBlacklist = "Are you sure you want to add #%s# to your blacklist?"
#Confirm overwriting folder
confirmOverwrite = "Are you sure you want to overwrite #%s#?"
#Confirm restoring save
confirmRestore = "Are you sure you want to restore #%s#?"
#Confirm deleting.
confirmDelete = "Are you sure you want to delete #%s#? *This is permanent*!"
#Confirm file copy in file mode
confirmCopy = "Are you sure you want to copy #%s# to #%s#?"
#Warning for erasing save data from system in title menu
confirmEraseNand = "*WARNING*: This *will* erase the save data for #%s# *from your system*. This is the same as deleting it from #Data Management#! Are you sure you want to continue?"
#Warning for deleting save data in folder menu
confirmEraseFolder = "*WARNING*: This *will* delete the current save data for #%s# *from your system*! Are you sure you want to continue?"
#Error displayed in pop-up if no titles are found for user. Rarely happens, but can for Device and BCAT
noSavesFound = "No save data found for #%s#!"
#Error pop-up displayed when git can't be connected to
errorConnecting = "Error Connecting!"
#Pop-up shown when no updates are found on git
noUpdate = "No updates available!"
#Text displayed when holding is required. Should have a trailing space
#If author is not "NULL", your name will be displayed in the UI
author = 0, "NULL"
confirmBlacklist = 0, "Are you sure you want to add #%s# to your blacklist?"
confirmCopy = 0, "Are you sure you want to copy #%s# to #%s#?"
confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
dialogNo = 0, "No [B]"
dialogYes = 0, "Yes [A]"
extrasMenu = 0, "SD to SD Browser"
extrasMenu = 1, "BIS: ProdInfoF"
extrasMenu = 2, "BIS: Safe"
extrasMenu = 3, "BIS: System"
extrasMenu = 4, "BIS: User"
extrasMenu = 5, "Remove Pending Update"
extrasMenu = 6, "Terminate Process"
extrasMenu = 7, "Mount System Save"
extrasMenu = 8, "Rescan Titles"
extrasMenu = 9, "Mount Process RomFS"
extrasMenu = 10, "Backup JKSV Folder"
extrasMenu = 11, "*[DEV]* Output en-US"
fileModeMenu = 0, "Copy To "
fileModeMenu = 1, "Delete"
fileModeMenu = 2, "Rename"
fileModeMenu = 3, "Make Dir"
fileModeMenu = 4, "Properties"
fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
#Menu options are held in arrays of strings.
#The number is the option to set, string is what to set to.
#Only the string after the comma needs to be edited.
#Adv/file mode menu
#'Copy to ' NEEDS a trailing space
advMenu = 0, "Copy to "
advMenu = 1, "Delete"
advMenu = 2, "Rename"
advMenu = 3, "Make Dir"
advMenu = 4, "Properties"
advMenu = 5, "Close"
#Extras Menu
extMenu = 0, "SD to SD Browser"
extMenu = 1, "BIS: PRODINFOF"
extMenu = 2, "BIS: SAFE"
extMenu = 3, "BIS: SYSTEM"
extMenu = 4, "BIS: USER"
extMenu = 5, "Remove Update"
extMenu = 6, "Terminate Process"
extMenu = 7, "Mount System Save"
extMenu = 8, "Rescan Titles"
extMenu = 9, "Mount Process RomFS"
extMenu = 10, "Backup JKSV Folder"
#Options menu
#All options need a trailing space. It is the most likely to have things added to it.
optMenu = 0, "Include Dev Sv: "
optMenu = 1, "AutoBackup: "
optMenu = 2, "Overclock: "
optMenu = 3, "Hold to Delete: "
optMenu = 4, "Hold to Restore: "
optMenu = 5, "Hold to Overwrite: "
optMenu = 6, "Force Mount: "
optMenu = 7, "Account Sys. Saves: "
optMenu = 8, "Write to Sys. Saves: "
optMenu = 9, "Text UI Mode: "
optMenu = 10, "Direct FS Cmd: "
optMenu = 11, "Skip User Select: "
optMenu = 12, "Export to ZIP: "
optMenu = 13, "Sort: "
optMenu = 14, "Language Override: "
#Explanations of what options do.
optMenuExp = 0, "Includes Device Save data in user accounts."
optMenuExp = 1, "Automatically creates a save backup before restoring a save."
optMenuExp = 2, "Applies a small CPU overclock to 1224Mhz at boot. This is the same speed developer units run at."
optMenuExp = 3, "Whether or not holding [A] is required when deleting folders and files."
optMenuExp = 4, "Whether or not holding [A] is required when restoring save data."
optMenuExp = 5, "Whether or not holding [A] is required when overwriting saves on SD."
optMenuExp = 6, "When enabled, JKSV will only load and show save data that can be opened. When disabled, everything found will be shown."
optMenuExp = 7, "When enabled, system save data tied to accounts will be shown."
optMenuExp = 8, "Controls whether system save data and partitions can have files and data written and deleted from them. *This can be extremely dangerous if you don't know what you're doing!*"
optMenuExp = 9, "Changes the UI to be text menu based like the original JKSM for 3DS."
optMenuExp = 10, "Directly uses the Switch's FS commands to copy files instead of stdio."
optMenuExp = 11, "Skips the user selection screen and jumps directly to the first user account found."
optMenuExp = 12, "Exports saves to zip files."
optMenuExp = 13, "Changes the way titles are sorted and listed."
opeMenuExp = 14, "Forces English to be used regardless of system language."
#Sort Types
onlineErrorConnecting = 0, "Error Connecting!"
onlineNoUpdates = 0, "No Updates Available."
popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popErrorCommittingFile = 0, "Error committing file to save!"
popProcessShutdown = 0, "#%s# successfully shutdown."
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
saveDataCreatedForUser = 0, "Save data created for %s!"
saveDataCreationFailed = 0, "Save data creation failed!"
saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %s?*"
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
settingsMenu = 0, "Empty Trash Bin"
settingsMenu = 1, "Check for Updates"
settingsMenu = 2, "Set JKSV Save Output Folder"
settingsMenu = 3, "Include Device Saves With Users: "
settingsMenu = 4, "Auto Backup On Restore: "
settingsMenu = 5, "Overclock/CPU Boost: "
settingsMenu = 6, "Hold To Delete: "
settingsMenu = 7, "Hold To Restore: "
settingsMenu = 8, "Hold To Overwrite: "
settingsMenu = 9, "Force Mount: "
settingsMenu = 10, "Account System Saves: "
settingsMenu = 11, "Enable Writing to System Saves: "
settingsMenu = 12, "Use FS Commands Directly: "
settingsMenu = 13, "Export Saves to ZIP: "
settingsMenu = 14, "Force English To Be Used: "
settingsMenu = 15, "Enable Trash Bin: "
settingsMenu = 16, "Title Sorting Type: "
settingsMenu = 17, "Animation Scale: "
settingsOff = 0, "Off"
settingsOn = 0, ">On>"
sortType = 0, "Alphabetical"
sortType = 1, "Time Played"
sortType = 2, "Last Played"
swkbdEnterName = 0, "Enter a new name"
swkbdMkDir = 0, "Enter a folder name"
swkbdProcessID = 0, "Enter Process ID"
swkbdRename = 0, "Enter a new name for item"
swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusResettingSaveData = 0, "Resetting save data..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
titleOptions = 3, "Open in File Mode"
titleOptions = 4, "Reset Save Data"
titleOptions = 5, "Delete Save Data"
titleOptions = 6, "Extend Save Data"
userOptions = 0, "Create Save Data"
userOptions = 1, "Create All Save Data"
userOptions = 2, "Delete All User Saves"

View File

@ -14,13 +14,13 @@ static std::vector<uint64_t> blacklist;
static std::vector<uint64_t> favorites;
static std::unordered_map<uint64_t, std::string> pathDefs;
uint8_t cfg::sortType;
const char *cfgPath = "sdmc:/config/JKSV/JKSV.cfg";
const char *cfgPath = "sdmc:/config/JKSV/JKSV.cfg", *titleDefPath = "sdmc:/config/JKSV/titleDefs.txt", *workDirLegacy = "sdmc:/switch/jksv_dir.txt";
static std::unordered_map<std::string, unsigned> cfgStrings =
{
{"workDir", 0}, {"includeDeviceSaves", 1}, {"autoBackup", 2}, {"overclock", 3}, {"holdToDelete", 4}, {"holdToRestore", 5},
{"holdToOverwrite", 6}, {"forceMount", 7}, {"accountSystemSaves", 8}, {"allowSystemSaveWrite", 9}, {"directFSCommands", 10},
{"exportToZIP", 11}, {"languageOverride", 12}, {"enableTrashBin", 13}, {"titleSortType", 14}, {"animationScale", 15},
{"favorite", 16}, {"blacklist", 17}, {"pathDef", 18}
{"favorite", 16}, {"blacklist", 17}
};
const std::string _true_ = "true", _false_ = "false";
@ -37,7 +37,8 @@ bool cfg::isBlacklisted(const uint64_t& tid)
void cfg::addTitleToBlacklist(void *a)
{
threadInfo *t = (threadInfo *)a;
uint64_t tid = data::curData.saveID;
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
uint64_t tid = d->saveID;
blacklist.push_back(tid);
for(data::user& u : data::users)
{
@ -169,8 +170,105 @@ static inline std::string sortTypeText()
return "";
}
static void loadWorkDirLegacy()
{
if(fs::fileExists(workDirLegacy))
{
char tmp[256];
memset(tmp, 0, 256);
FILE *getDir = fopen(workDirLegacy, "r");
fgets(tmp, FS_MAX_PATH, getDir);
fclose(getDir);
std::string tmpStr = tmp;
util::stripChar('\n', tmpStr);
util::stripChar('\r', tmpStr);
fs::setWorkDir(tmpStr);
fs::delfile(workDirLegacy);
}
}
static void loadConfigLegacy()
{
std::string legacyCfgPath = fs::getWorkDir() + "cfg.bin";
if(fs::fileExists(legacyCfgPath))
{
FILE *oldCfg = fopen(legacyCfgPath.c_str(), "rb");
uint64_t cfgIn = 0;
fread(&cfgIn, sizeof(uint64_t), 1, oldCfg);
fread(&cfg::sortType, 1, 1, oldCfg);
fread(&ui::animScale, sizeof(float), 1, oldCfg);
if(ui::animScale == 0)
ui::animScale = 3.0f;
fclose(oldCfg);
cfg::config["incDev"] = cfgIn >> 63 & 1;
cfg::config["autoBack"] = cfgIn >> 62 & 1;
cfg::config["ovrClk"] = cfgIn >> 61 & 1;
cfg::config["holdDel"] = cfgIn >> 60 & 1;
cfg::config["holdRest"] = cfgIn >> 59 & 1;
cfg::config["holdOver"] = cfgIn >> 58 & 1;
cfg::config["forceMount"] = cfgIn >> 57 & 1;
cfg::config["accSysSave"] = cfgIn >> 56 & 1;
cfg::config["sysSaveWrite"] = cfgIn >> 55 & 1;
cfg::config["directFsCmd"] = cfgIn >> 53 & 1;
cfg::config["zip"] = cfgIn >> 51 & 1;
cfg::config["langOverride"] = cfgIn >> 50 & 1;
cfg::config["trashBin"] = cfgIn >> 49 & 1;
fs::delfile(cfgPath);
}
}
static void loadFavoritesLegacy()
{
std::string legacyFavPath = fs::getWorkDir() + "favorites.txt";
if(fs::fileExists(legacyFavPath))
{
fs::dataFile fav(legacyFavPath);
while(fav.readNextLine(false))
favorites.push_back(strtoul(fav.getLine().c_str(), NULL, 16));
fav.close();
fs::delfile(legacyFavPath);
}
}
static void loadBlacklistLegacy()
{
std::string legacyBlPath = fs::getWorkDir() + "blacklist.txt";
if(fs::fileExists(legacyBlPath))
{
fs::dataFile bl(legacyBlPath);
while(bl.readNextLine(false))
blacklist.push_back(strtoul(bl.getLine().c_str(), NULL, 16));
bl.close();
fs::delfile(legacyBlPath);
}
}
static void loadTitleDefs()
{
std::string titleDefLegacy = fs::getWorkDir() + "titleDefs.txt";
if(fs::fileExists(titleDefLegacy))
rename(titleDefLegacy.c_str(), titleDefPath);
if(fs::fileExists(titleDefPath))
{
fs::dataFile getPaths(titleDefPath);
while(getPaths.readNextLine(true))
{
uint64_t tid = strtoul(getPaths.getName().c_str(), NULL, 16);
pathDefs[tid] = getPaths.getNextValueStr();
}
}
}
void cfg::loadConfig()
{
loadWorkDirLegacy();
loadConfigLegacy();
loadFavoritesLegacy();
loadBlacklistLegacy();
if(fs::fileExists(cfgPath))
{
fs::dataFile cfgRead(cfgPath);
@ -256,7 +354,7 @@ void cfg::loadConfig()
case 16:
{
std::string tid = cfgRead.getNextValueStr();
favorites.push_back(strtoul(tid.c_str(), NULL, 16));
favorites.push_back(strtoul(tid.c_str(), NULL, 16));
}
break;
@ -266,16 +364,18 @@ void cfg::loadConfig()
blacklist.push_back(strtoul(tid.c_str(), NULL, 16));
}
break;
case 18:
{
uint64_t tid = strtoul(cfgRead.getNextValueStr().c_str(), NULL, 16);
pathDefs[tid] = cfgRead.getNextValueStr();
}
break;
}
}
}
loadTitleDefs();
}
static void savePathDefs()
{
FILE *pathOut = fopen(titleDefPath, "w");
for(auto& p : pathDefs)
fprintf(pathOut, "0x%016lX = \"%s\"\n", p.first, p.second.c_str());
fclose(pathOut);
}
void cfg::saveConfig()
@ -287,7 +387,7 @@ void cfg::saveConfig()
fprintf(cfgOut, "overclock = %s\n", boolToText(cfg::config["ovrClk"]).c_str());
fprintf(cfgOut, "holdToDelete = %s\n", boolToText(cfg::config["holdDel"]).c_str());
fprintf(cfgOut, "holdToRestore = %s\n", boolToText(cfg::config["holdRest"]).c_str());
fprintf(cfgOut, "holdToOverwrite = %s\n", boolToText(cfg::config["autoOver"]).c_str());
fprintf(cfgOut, "holdToOverwrite = %s\n", boolToText(cfg::config["holdOver"]).c_str());
fprintf(cfgOut, "forceMount = %s\n", boolToText(cfg::config["forceMount"]).c_str());
fprintf(cfgOut, "accountSystemSaves = %s\n", boolToText(cfg::config["accSysSaves"]).c_str());
fprintf(cfgOut, "allowSystemSaveWrite = %s\n", boolToText(cfg::config["sysSaveWrite"]).c_str());
@ -311,12 +411,8 @@ void cfg::saveConfig()
for(uint64_t& b : blacklist)
fprintf(cfgOut, "blacklist = 0x%016lX\n", b);
}
fclose(cfgOut);
if(!pathDefs.empty())
{
fprintf(cfgOut, "\n#Output Path Definitions\n");
for(auto& p : pathDefs)
fprintf(cfgOut, "pathDef(0x%016lX, \"%s\")\n", p.first, p.second.c_str());
}
fclose(cfgOut);
savePathDefs();
}

View File

@ -16,7 +16,7 @@
//FsSaveDataSpaceId_All doesn't work for SD
static const unsigned saveOrder [] = { 0, 1, 2, 3, 4, 100, 101 };
int data::selUser = 0, data::selData = 0;
int selUser = 0, selData = 0;
//User vector
std::vector<data::user> data::users;
@ -328,6 +328,36 @@ void data::exit()
util::setCPU(1020000000);
}
void data::setUserIndex(unsigned _sUser)
{
selUser = _sUser;
}
data::user *data::getCurrentUser()
{
return &users[selUser];
}
unsigned data::getCurrentUserIndex()
{
return selUser;
}
void data::setTitleIndex(unsigned _sTitle)
{
selData = _sTitle;
}
data::userTitleInfo *data::getCurrentUserTitleInfo()
{
return &users[selUser].titleInfo[selData];
}
unsigned data::getCurrentUserTitleInfoIndex()
{
return selData;
}
data::titleInfo *data::getTitleInfoByTID(const uint64_t& tid)
{
if(titles.find(tid) != titles.end())
@ -413,13 +443,16 @@ static const SDL_Color green = {0x00, 0xDD, 0x00, 0xFF};
void data::dispStats()
{
data::user *cu = data::getCurrentUser();
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
//Easiest/laziest way to do this
std::string stats = "User Count: " + std::to_string(users.size()) + "\n";
for(data::user& u : data::users)
stats += u.getUsername() + ": " + std::to_string(u.titleInfo.size()) + "\n";
stats += "Current User: " + data::curUser.getUsername() + "\n";
stats += "Current Title: " + data::getTitleNameByTID(data::curData.saveID) + "\n";
stats += "Safe Title: " + data::getTitleSafeNameByTID(data::curData.saveID) + "\n";
stats += "Current User: " + cu->getUsername() + "\n";
stats += "Current Title: " + data::getTitleNameByTID(d->saveID) + "\n";
stats += "Safe Title: " + data::getTitleSafeNameByTID(d->saveID) + "\n";
stats += "Sort Type: " + std::to_string(cfg::sortType) + "\n";
gfx::drawTextf(NULL, 16, 2, 2, &green, stats.c_str());
}

View File

@ -87,12 +87,27 @@ bool fs::commitToDevice(const std::string& dev)
if(R_FAILED(res))
{
fs::logWrite("Error committing file to device -> 0x%X\n", res);
ui::showPopMessage(POP_FRAME_DEFAULT, "Error committing file to device!");
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popErrorCommittingFile", 0));
ret = false;
}
return ret;
}
void fs::createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _userID)
{
std::string indexStr;
uint16_t index = 0;
if(_type == FsSaveDataType_Cache && !(indexStr = util::getStringInput(SwkbdType_NumPad, "0", ui::getUIString("swkbdSaveIndex", 0), 3, 0, NULL)).empty())
index = strtoul(indexStr.c_str(), NULL, 10);
svCreateArgs *send = new svCreateArgs;
send->type = _type;
send->account = _userID;
send->tid = _tid;
send->index = index;
ui::newThread(fs::createSaveData_t, send, NULL);
}
void fs::init()
{
mkDirRec("sdmc:/config/JKSV/");
@ -343,7 +358,7 @@ void fs::copyDirToZip(const std::string& from, zipFile to)
if(cfg::config["ovrClk"])
{
util::setCPU(1785000000);
ui::showPopMessage(POP_FRAME_DEFAULT, "CPU Boost Enabled for ZIP.");
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popCPUBoostEnabled", 0));
}
copyArgs *send = copyArgsCreate(from, "", "", to, NULL, true);
ui::newThread(copyDirToZip_t, send, _fileDrawFunc);
@ -354,7 +369,7 @@ void fs::copyZipToDir(unzFile unz, const std::string& to, const std::string& dev
if(cfg::config["ovrClk"])
{
util::setCPU(1785000000);
ui::showPopMessage(POP_FRAME_DEFAULT, "CPU Boost Enabled for ZIP.");
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popCPUBoostEnabled", 0));
}
copyArgs *send = copyArgsCreate("", to, dev, NULL, unz, true);
ui::newThread(copyZipToDir_t, send, _fileDrawFunc);
@ -579,14 +594,18 @@ void fs::createNewBackup(void *a)
{
uint64_t held = ui::padKeysHeld();
data::user *u = data::getCurrentUser();
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
data::titleInfo *t = data::getTitleInfoByTID(d->saveID);
std::string out;
if(held & HidNpadButton_R)
out = data::users[data::selUser].getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD);
out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD);
else if(held & HidNpadButton_L)
out = data::users[data::selUser].getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YDM);
out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YDM);
else if(held & HidNpadButton_ZL)
out = data::users[data::selUser].getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_HOYSTE);
out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_HOYSTE);
else
{
const std::string dict[] =
@ -596,19 +615,19 @@ void fs::createNewBackup(void *a)
util::getDateTime(util::DATE_FMT_HOYSTE),
util::getDateTime(util::DATE_FMT_JHK),
util::getDateTime(util::DATE_FMT_ASC),
data::users[data::selUser].getUsernameSafe(),
data::getTitleInfoByTID(data::curData.saveID)->safeTitle,
util::generateAbbrev(data::curData.saveID),
u->getUsernameSafe(),
t->safeTitle,
util::generateAbbrev(d->saveID),
".zip"
};
std::string defaultText = data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD);
out = util::getStringInput(SwkbdType_QWERTY, defaultText, "Enter a name", 64, 9, dict);
std::string defaultText = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD);
out = util::getStringInput(SwkbdType_QWERTY, defaultText, ui::getUIString("swkbdEnterName", 0), 64, 9, dict);
}
if(!out.empty())
{
std::string ext = util::getExtensionFromString(out);
std::string path = util::generatePathByTID(data::curData.saveID) + out;
std::string path = util::generatePathByTID(d->saveID) + out;
if(cfg::config["zip"] || ext == "zip")
{
if(ext != "zip")//data::zip is on but extension is not zip
@ -635,12 +654,14 @@ void fs::overwriteBackup(void *a)
ui::menu *m = in->m;
fs::dirList *d = in->d;
data::userTitleInfo *cd = data::getCurrentUserTitleInfo();
unsigned ind = m->getSelected() - 1;;//Skip new
std::string itemName = d->getItem(ind);
if(d->isDir(ind))
{
std::string toPath = util::generatePathByTID(data::curData.saveID) + itemName + "/";
std::string toPath = util::generatePathByTID(cd->saveID) + itemName + "/";
//Delete and recreate
fs::delDir(toPath);
mkdir(toPath.c_str(), 777);
@ -648,7 +669,7 @@ void fs::overwriteBackup(void *a)
}
else if(!d->isDir(ind) && d->getItemExt(ind) == "zip")
{
std::string toPath = util::generatePathByTID(data::curData.saveID) + itemName;
std::string toPath = util::generatePathByTID(cd->saveID) + itemName;
fs::delfile(toPath);
zipFile zip = zipOpen64(toPath.c_str(), 0);
fs::copyDirToZip("sv:/", zip);
@ -663,27 +684,29 @@ void fs::restoreBackup(void *a)
ui::menu *m = in->m;
fs::dirList *d = in->d;
data::user *u = data::getCurrentUser();
data::userTitleInfo *cd = data::getCurrentUserTitleInfo();
unsigned ind = m->getSelected() - 1;
std::string itemName = d->getItem(ind);
if((data::curData.saveInfo.save_data_type != FsSaveDataType_System || cfg::config["sysSaveWrite"]) && m->getSelected() > 0)
if((cd->saveInfo.save_data_type != FsSaveDataType_System || cfg::config["sysSaveWrite"]) && m->getSelected() > 0)
{
if(cfg::config["autoBack"] && cfg::config["zip"])
{
std::string autoZip = util::generatePathByTID(data::curData.saveID) + "/AUTO " + data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip";
std::string autoZip = util::generatePathByTID(cd->saveID) + "/AUTO " + u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip";
zipFile zip = zipOpen64(autoZip.c_str(), 0);
fs::copyDirToZip("sv:/", zip);
}
else if(cfg::config["autoBack"])
{
std::string autoFolder = util::generatePathByTID(data::curData.saveID) + "/AUTO - " + data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/";
std::string autoFolder = util::generatePathByTID(cd->saveID) + "/AUTO - " + u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/";
mkdir(autoFolder.substr(0, autoFolder.length() - 1).c_str(), 777);
fs::copyDirToDir("sv:/", autoFolder);
}
if(d->isDir(ind))
{
std::string fromPath = util::generatePathByTID(data::curData.saveID) + itemName + "/";
std::string fromPath = util::generatePathByTID(cd->saveID) + itemName + "/";
if(fs::dirNotEmpty(fromPath))
{
fs::wipeSave();
@ -694,7 +717,7 @@ void fs::restoreBackup(void *a)
}
else if(!d->isDir(ind) && d->getItemExt(ind) == "zip")
{
std::string path = util::generatePathByTID(data::curData.saveID) + itemName;
std::string path = util::generatePathByTID(cd->saveID) + itemName;
unzFile unz = unzOpen64(path.c_str());
if(unz && fs::zipNotEmpty(unz))
{
@ -707,7 +730,7 @@ void fs::restoreBackup(void *a)
else
{
//Just copy file over
std::string fromPath = util::generatePathByTID(data::curData.saveID) + itemName;
std::string fromPath = util::generatePathByTID(cd->saveID) + itemName;
std::string toPath = "sv:/" + itemName;
fs::copyFileCommit(fromPath, toPath, "sv");
}
@ -726,29 +749,29 @@ void fs::deleteBackup(void *a)
ui::menu *m = in->m;
fs::dirList *d = in->d;
data::userTitleInfo *cd = data::getCurrentUserTitleInfo();
unsigned ind = m->getSelected() - 1;
std::string itemName = d->getItem(ind);
t->status->setStatus("Deleting '" + itemName + "'...");
t->status->setStatus("Deleting...");
if(cfg::config["trashBin"])
{
std::string oldPath = util::generatePathByTID(data::curData.saveID) + itemName;
std::string oldPath = util::generatePathByTID(cd->saveID) + itemName;
std::string trashPath = wd + "_TRASH_/" + itemName;
rename(oldPath.c_str(), trashPath.c_str());
ui::showPopMessage(POP_FRAME_DEFAULT, "%s moved to trash.", itemName.c_str());
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupMovedToTrash", 0), itemName.c_str());
}
else if(d->isDir(ind))
{
std::string delPath = util::generatePathByTID(data::curData.saveID) + itemName + "/";
std::string delPath = util::generatePathByTID(cd->saveID) + itemName + "/";
fs::delDir(delPath);
ui::showPopMessage(POP_FRAME_DEFAULT, "%s has been deleted.", itemName.c_str());
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), itemName.c_str());
}
else
{
std::string delPath = util::generatePathByTID(data::curData.saveID) + itemName;
std::string delPath = util::generatePathByTID(cd->saveID) + itemName;
fs::delfile(delPath);
ui::showPopMessage(POP_FRAME_DEFAULT, "%s has been deleted.", itemName.c_str());
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), itemName.c_str());
}
ui::populateFldMenu();
t->finished = true;

View File

@ -7,7 +7,8 @@
static uint64_t getJournalSize(const data::titleInfo *t)
{
uint64_t journalSize = 0;
switch(data::curData.saveInfo.save_data_type)
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
switch(d->saveInfo.save_data_type)
{
case FsSaveDataType_Account:
journalSize = t->nacp.user_account_save_data_journal_size;
@ -49,11 +50,90 @@ void fs::_fileDrawFunc(void *a)
}
}
void fs::createSaveData_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::svCreateArgs *s = (fs::svCreateArgs *)t->argPtr;
data::titleInfo *create = data::getTitleInfoByTID(s->tid);
t->status->setStatus(ui::getUICString("threadStatusCreatingSaveData", 0), create->title.c_str());
FsSaveDataAttribute attr;
memset(&attr, 0, sizeof(FsSaveDataAttribute));
attr.application_id = s->tid;
attr.uid = s->account;
attr.system_save_data_id = 0;
attr.save_data_type = s->type;
attr.save_data_rank = 0;
attr.save_data_index = s->index;
FsSaveDataCreationInfo svCreate;
memset(&svCreate, 0, sizeof(FsSaveDataCreationInfo));
int64_t saveSize = 0, journalSize = 0;
switch(s->type)
{
case FsSaveDataType_Account:
saveSize = create->nacp.user_account_save_data_size;
journalSize = create->nacp.user_account_save_data_journal_size;
break;
case FsSaveDataType_Device:
saveSize = create->nacp.device_save_data_size;
journalSize = create->nacp.device_save_data_journal_size;
break;
case FsSaveDataType_Bcat:
saveSize = create->nacp.bcat_delivery_cache_storage_size;
journalSize = create->nacp.bcat_delivery_cache_storage_size;
break;
case FsSaveDataType_Cache:
saveSize = 32 * 1024 * 1024;//Todo: Add target folder/zip selection for size
if(create->nacp.cache_storage_journal_size > create->nacp.cache_storage_data_and_journal_size_max)
journalSize = create->nacp.cache_storage_journal_size;
else
journalSize = create->nacp.cache_storage_data_and_journal_size_max;
break;
default:
delete s;
t->finished = true;
return;
break;
}
svCreate.save_data_size = saveSize;
svCreate.journal_size = journalSize;
svCreate.available_size = 0x4000;
svCreate.owner_id = create->nacp.save_data_owner_id;
svCreate.flags = 0;
svCreate.save_data_space_id = FsSaveDataSpaceId_User;
FsSaveDataMetaInfo meta;
memset(&meta, 0, sizeof(FsSaveDataMetaInfo));
meta.size = 0x40060;
meta.type = FsSaveDataMetaType_Thumbnail;
Result res = 0;
if(R_SUCCEEDED(res = fsCreateSaveDataFileSystem(&attr, &svCreate, &meta)))
{
util::createTitleDirectoryByTID(s->tid);
data::loadUsersTitles(false);
ui::ttlRefresh();
}
else
{
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataCreationFailed", 0));
fs::logWrite("SaveCreate Failed -> %X\n", res);
}
delete s;
t->finished = true;
}
void fs::copyFile_t(void *a)
{
threadInfo *t = (threadInfo *)a;
copyArgs *args = (copyArgs *)t->argPtr;
t->status->setStatus("Copying '" + args->from + "'...");
t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), args->from.c_str());
args->prog->setMax(fs::fsize(args->from));
args->prog->update(0);
@ -117,8 +197,9 @@ void fs::copyFileCommit_t(void *a)
{
threadInfo *t = (threadInfo *)a;
copyArgs *args = (copyArgs *)t->argPtr;
data::titleInfo *info = data::getTitleInfoByTID(data::curData.saveID);
t->status->setStatus("Copying '" + args->from + "'...");
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
data::titleInfo *info = data::getTitleInfoByTID(d->saveID);
t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), args->from.c_str());
args->prog->setMax(fs::fsize(args->from));
args->prog->update(0);
@ -316,7 +397,7 @@ void fs::copyDirToZip_t(void *a)
threadInfo *t = (threadInfo *)a;
copyArgs *args = (copyArgs *)t->argPtr;
t->status->setStatus("Opening " + args->from + "...");
t->status->setStatus(ui::getUICString("threadStatusOpeningFolder", 0), args->from.c_str());
fs::dirList *list = new fs::dirList(args->from);
unsigned listTotal = list->getCount();
@ -346,7 +427,7 @@ void fs::copyDirToZip_t(void *a)
zip_fileinfo inf = {0};
std::string filename = args->from + itm;
size_t devPos = filename.find_first_of('/') + 1;
t->status->setStatus("Adding '" + itm + "' to ZIP.");
t->status->setStatus(ui::getUICString("threadStatusAddingFileToZip", 0), itm.c_str());
int zOpenFile = zipOpenNewFileInZip64(args->z, filename.substr(devPos, filename.length()).c_str(), &inf, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0);
if(zOpenFile == ZIP_OK)
{
@ -386,7 +467,8 @@ void fs::copyZipToDir_t(void *a)
threadInfo *t = (threadInfo *)a;
copyArgs *args = (copyArgs *)t->argPtr;
data::titleInfo *tinfo = data::getTitleInfoByTID(data::curData.saveID);
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
data::titleInfo *tinfo = data::getTitleInfoByTID(d->saveID);
uint64_t journalSize = getJournalSize(tinfo), writeCount = 0;
char filename[FS_MAX_PATH];
uint8_t *buff = new uint8_t[BUFF_SIZE];
@ -397,7 +479,7 @@ void fs::copyZipToDir_t(void *a)
unzGetCurrentFileInfo64(args->unz, &info, filename, FS_MAX_PATH, NULL, 0, NULL, 0);
if(unzOpenCurrentFile(args->unz) == UNZ_OK)
{
t->status->setStatus("Copying '" + std::string(filename) + "'...");
t->status->setStatus(ui::getUICString("threadStatusDecompressingFile", 0), filename);
std::string path = args->to + filename;
mkDirRec(path.substr(0, path.find_last_of('/') + 1));
@ -470,7 +552,7 @@ void fs::copyZipToDir_t(void *a)
void fs::wipesave_t(void *a)
{
threadInfo *t = (threadInfo *)a;
t->status->setStatus("Resetting current save...");
t->status->setStatus(ui::getUICString("threadStatusResettingSaveData", 0));
fs::delDir("sv:/");
fs::commitToDevice("sv");
t->finished = true;

25
src/type.cpp Normal file
View File

@ -0,0 +1,25 @@
#include <switch.h>
#include <stdio.h>
#include <stdarg.h>
#include "type.h"
void threadStatus::setStatus(const char *fmt, ...)
{
char tmp[1024];
va_list args;
va_start(args, fmt);
vsprintf(tmp, fmt, args);
va_end(args);
mutexLock(&statusLock);
status = tmp;
mutexUnlock(&statusLock);
}
void threadStatus::getStatus(std::string& statusOut)
{
mutexLock(&statusLock);
statusOut = status;
mutexUnlock(&statusLock);
}

View File

@ -46,8 +46,6 @@ SDL_Texture *ui::sideBar;
static SDL_Texture *icn, *corePanel;
SDL_Color ui::heartColor = {0xFF, 0x44, 0x44, 0xFF};
//X position of help texts. Calculated to make editing quicker/easier
static unsigned userHelpX, titleHelpX, folderHelpX, optHelpX;
static int settPos, extPos;
//Vector of pointers to slideOutPanels. Is looped and drawn last so they are always on top
@ -77,7 +75,7 @@ void ui::initTheme()
rectSh = {0xCA, 0xCA, 0xCA, 0xFF};
tboxClr = {0xEB, 0xEB, 0xEB, 0xFF};
divClr = {0x00, 0x00, 0x00, 0xFF};
slidePanelColor = {0xEE, 0xEE, 0xEE, 0xDD};
slidePanelColor = {0xEE, 0xEE, 0xEE, 0xEE};
break;
default:
@ -91,7 +89,7 @@ void ui::initTheme()
rectSh = {0x20, 0x20, 0x20, 0xFF};
tboxClr = {0x50, 0x50, 0x50, 0xFF};
divClr = {0xFF, 0xFF, 0xFF, 0xFF};
slidePanelColor = {0x00, 0x00, 0x00, 0xDD};
slidePanelColor = {0x00, 0x00, 0x00, 0xEE};
break;
}
}
@ -136,18 +134,12 @@ void ui::init()
loadTrans();
//Replace the button [x] in strings that need it. Needs to be outside loadTrans so even defaults will get replaced
util::replaceButtonsInString(ui::userHelp);
util::replaceButtonsInString(ui::titleHelp);
util::replaceButtonsInString(ui::folderHelp);
util::replaceButtonsInString(ui::optHelp);
util::replaceButtonsInString(ui::yt);
util::replaceButtonsInString(ui::nt);
//Calculate x position of help text
userHelpX = 1220 - gfx::getTextWidth(ui::userHelp.c_str(), 18);
titleHelpX = 1220 - gfx::getTextWidth(ui::titleHelp.c_str(), 18);
folderHelpX = 1220 - gfx::getTextWidth(ui::folderHelp.c_str(), 18);
optHelpX = 1220 - gfx::getTextWidth(ui::optHelp.c_str(), 18);
util::replaceButtonsInString(ui::strings[std::make_pair("helpUser", 0)]);
util::replaceButtonsInString(ui::strings[std::make_pair("helpTitle", 0)]);
util::replaceButtonsInString(ui::strings[std::make_pair("helpFolder", 0)]);
util::replaceButtonsInString(ui::strings[std::make_pair("helpSettings", 0)]);
util::replaceButtonsInString(ui::strings[std::make_pair("dialogYes", 0)]);
util::replaceButtonsInString(ui::strings[std::make_pair("dialogNo", 0)]);
//setup pad
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
@ -231,8 +223,11 @@ void ui::drawUI()
//Version / translation author
gfx::drawTextf(NULL, 12, 8, 700, &ui::txtCont, "v. %02d.%02d.%04d", BLD_MON, BLD_DAY, BLD_YEAR);
if(author != "NULL")
gfx::drawTextf(NULL, 12, 8, 682, &ui::txtCont, "Translation: %s", author.c_str());
if(ui::getUIString("author", 0) != "NULL")
gfx::drawTextf(NULL, 12, 8, 682, &ui::txtCont, "Translation: %s", ui::getUICString("author", 0));
//This only draws the help text now and only does when user select is open
ui::usrDraw(NULL);
if((ui::usrMenu->getActive() && ui::usrMenu->getSelected() == settPos) || ui::mstate == OPT_MNU)
ui::settDraw(corePanel);
@ -316,12 +311,17 @@ void ui::showPopMessage(int frameCount, const char *fmt, ...)
void ui::toTTL(void *a)
{
if(data::curUser.titleInfo.size() > 0)
data::user *u = data::getCurrentUser();
unsigned curUserIndex = data::getCurrentUserIndex();
if(u->titleInfo.size() > 0)
{
ui::changeState(TTL_SEL);
ui::ttlSetActive(data::selUser);
ui::ttlSetActive(curUserIndex);
ui::usrMenu->setActive(false);
}
else
ui::showPopMessage(POP_FRAME_DEFAULT, ui::noSavesFound.c_str(), data::curUser.getUsername().c_str());
{
data::user *u = data::getCurrentUser();
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataNoneFound", 0), u->getUsername().c_str());
}
}

View File

@ -75,7 +75,7 @@ static void toFMUser(void *a)
static void _delUpdate(void *a)
{
threadInfo *t = (threadInfo *)a;
t->status->setStatus("Deleting update from NAND...");
t->status->setStatus(ui::getUICString("threadStatusDeletingUpdate", 0));
FsFileSystem sys;
fsOpenBisFileSystem(&sys, FsBisPartitionId_System, "");
fsdevMountDevice("sys", sys);
@ -91,19 +91,19 @@ static void extMenuOptRemoveUpdate(void *a)
static void extMenuTerminateProcess(void *a)
{
std::string idStr = util::getStringInput(SwkbdType_QWERTY, "0100000000000000", "Enter Process ID", 18, 0, NULL);
std::string idStr = util::getStringInput(SwkbdType_QWERTY, "0100000000000000", ui::getUIString("swkbdProcessID", 0), 18, 0, NULL);
if(!idStr.empty())
{
uint64_t termID = std::strtoull(idStr.c_str(), NULL, 16);
if(R_SUCCEEDED(pmshellTerminateProgram(termID)))
ui::showPopMessage(POP_FRAME_DEFAULT, "Process %s successfully shutdown.", idStr.c_str());
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popProcessShutdown", 0), idStr.c_str());
}
}
static void extMenuMountSysSave(void *a)
{
FsFileSystem sys;
std::string idStr = util::getStringInput(SwkbdType_QWERTY, "8000000000000000", "Enter Sys Save ID", 18, 0, NULL);
std::string idStr = util::getStringInput(SwkbdType_QWERTY, "8000000000000000", ui::getUIString("swkbdSysSavID", 0), 18, 0, NULL);
uint64_t mountID = std::strtoull(idStr.c_str(), NULL, 16);
if(R_SUCCEEDED(fsOpen_SystemSaveData(&sys, FsSaveDataSpaceId_System, mountID, (AccountUid) {0})))
{
@ -134,13 +134,18 @@ static void extMenuMountRomFS(void *a)
}
}
static void extMenuOutputEnUs(void *a)
{
ui::newThread(ui::saveTranslationFile, NULL, NULL);
}
void ui::extInit()
{
ui::extMenu = new ui::menu(200, 24, 1002, 24, 4);
ui::extMenu->setCallback(extMenuCallback, NULL);
ui::extMenu->setActive(false);
for(unsigned i = 0; i < 11; i++)
ui::extMenu->addOpt(NULL, ui::exMenuStr[i]);
for(unsigned i = 0; i < 12; i++)
ui::extMenu->addOpt(NULL, ui::getUIString("extrasMenu", i));
//SD to SD
ui::extMenu->optAddButtonEvent(0, HidNpadButton_A, toFMSDtoSD, NULL);
@ -162,6 +167,8 @@ void ui::extInit()
ui::extMenu->optAddButtonEvent(8, HidNpadButton_A, extMenuReloadTitles, NULL);
//RomFS
ui::extMenu->optAddButtonEvent(9, HidNpadButton_A, extMenuMountRomFS, NULL);
//Translation so I can be lazy
ui::extMenu->optAddButtonEvent(11, HidNpadButton_A, extMenuOutputEnUs, NULL);
}
void ui::extExit()

View File

@ -249,7 +249,7 @@ static void _copyMenuCopy(void *a)
if(ma == devArgs || (ma == sdmcArgs && (type != FsSaveDataType_System || cfg::config["sysSaveWrite"])))
{
ui::confirmArgs *send = ui::confirmArgsCreate(false, _copyMenuCopy_t, ma, true, ui::confCopy.c_str(), srcPath.c_str(), dstPath.c_str());
ui::confirmArgs *send = ui::confirmArgsCreate(false, _copyMenuCopy_t, ma, true, ui::getUICString("confirmCopy", 0), srcPath.c_str(), dstPath.c_str());
ui::confirm(send);
}
}
@ -260,7 +260,7 @@ static void _copyMenuDelete_t(void *a)
menuFuncArgs *ma = (menuFuncArgs *)t->argPtr;
fs::backupArgs *b = ma->b;
t->status->setStatus("Deleting...");
t->status->setStatus(ui::getUICString("threadStatusDeletingFile", 0));
int sel = b->m->getSelected();
if(ma == devArgs)
@ -321,7 +321,7 @@ static void _copyMenuDelete(void *a)
if(ma == sdmcArgs || (ma == devArgs && (sel == 0 || sel > 1) && (type != FsSaveDataType_System || cfg::config["sysSaveWrite"])))
{
ui::confirmArgs *send = ui::confirmArgsCreate(cfg::config["holdDel"], _copyMenuDelete_t, a, true, ui::confDel.c_str(), itmPath.c_str());
ui::confirmArgs *send = ui::confirmArgsCreate(cfg::config["holdDel"], _copyMenuDelete_t, a, true, ui::getUICString("confirmDelete", 0), itmPath.c_str());
ui::confirm(send);
}
}
@ -334,7 +334,7 @@ static void _copyMenuRename(void *a)
int sel = b->m->getSelected();
if(sel > 1)
{
std::string getNewName = util::getStringInput(SwkbdType_QWERTY, b->d->getItem(sel - 2), "Enter a new name", 64, 0, NULL);
std::string getNewName = util::getStringInput(SwkbdType_QWERTY, b->d->getItem(sel - 2), ui::getUIString("swkbdRename", 0), 64, 0, NULL);
if(!getNewName.empty())
{
std::string prevPath = *ma->path + b->d->getItem(sel - 2);
@ -352,7 +352,7 @@ static void _copyMenuRename(void *a)
static void _copyMenuMkDir(void *a)
{
menuFuncArgs *ma = (menuFuncArgs *)a;
std::string getNewFolder = util::getStringInput(SwkbdType_QWERTY, "New Folder", "Enter a name", 64, 0, NULL);
std::string getNewFolder = util::getStringInput(SwkbdType_QWERTY, "New Folder", ui::getUIString("swkbdMkDir", 0), 64, 0, NULL);
if(!getNewFolder.empty())
{
std::string createPath = *ma->path + getNewFolder;
@ -390,9 +390,10 @@ static void _devMenuAddToPathFilter(void *a)
int sel = b->m->getSelected();
if(sel > 1)
{
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
std::string filterPath = *ma->path + b->d->getItem(sel - 2);
cfg::addPathToFilter(data::curData.saveID, filterPath);
ui::showPopMessage(POP_FRAME_DEFAULT, "'%s' added to path filter.", filterPath.c_str());
cfg::addPathToFilter(d->saveID, filterPath);
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popAddedToPathFilter", 0), filterPath.c_str());
}
}
@ -416,13 +417,13 @@ void ui::fmInit()
devCopyMenu = new ui::menu(10, 185, 268, 20, 5);
devCopyMenu->setActive(false);
devCopyMenu->setCallback(_devCopyMenuCallback, NULL);
devCopyMenu->addOpt(NULL, ui::advMenuStr[0] + "SDMC");
devCopyMenu->addOpt(NULL, ui::getUIString("fileModeMenu", 0) + "SDMC");
for(int i = 1; i < 4; i++)
devCopyMenu->addOpt(NULL, advMenuStr[i]);
devCopyMenu->addOpt(NULL, ui::getUIString("fileModeMenu", i));
//Manually do this so I can place the last option higher up
devCopyMenu->addOpt(NULL, advMenuStr[6]);
devCopyMenu->addOpt(NULL, advMenuStr[4]);
devCopyMenu->addOpt(NULL, advMenuStr[5]);
devCopyMenu->addOpt(NULL, ui::getUIString("fileModeMenu", 6));
devCopyMenu->addOpt(NULL, ui::getUIString("fileModeMenu", 4));
devCopyMenu->addOpt(NULL, ui::getUIString("fileModeMenu", 5));
devCopyMenu->optAddButtonEvent(0, HidNpadButton_A, _copyMenuCopy, devArgs);
devCopyMenu->optAddButtonEvent(1, HidNpadButton_A, _copyMenuDelete, devArgs);
@ -442,7 +443,7 @@ void ui::fmInit()
sdCopyMenu->setActive(false);
sdCopyMenu->setCallback(_sdCopyMenuCallback, NULL);
for(int i = 0; i < 6; i++)
sdCopyMenu->addOpt(NULL, advMenuStr[i]);
sdCopyMenu->addOpt(NULL, ui::getUIString("fileModeMenu", i));
sdCopyMenu->optAddButtonEvent(0, HidNpadButton_A, _copyMenuCopy, sdmcArgs);
sdCopyMenu->optAddButtonEvent(1, HidNpadButton_A, _copyMenuDelete, sdmcArgs);
sdCopyMenu->optAddButtonEvent(2, HidNpadButton_A, _copyMenuRename, sdmcArgs);
@ -478,7 +479,7 @@ void ui::fmPrep(const FsSaveDataType& _type, const std::string& _dev, bool _comm
devPath = _dev;
sdPath = "sdmc:/";
sdCopyMenu->editOpt(0, NULL, ui::advMenuStr[0] + _dev);
sdCopyMenu->editOpt(0, NULL, ui::getUIString("fileModeMenu", 0) + _dev);
devList->reassign(dev);
sdList->reassign(sdPath);

View File

@ -50,10 +50,16 @@ void ui::menu::editParam(int _param, int newVal)
case MENU_RECT_WIDTH:
rW = newVal;
SDL_DestroyTexture(optTex);
optTex = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, rW, rH);
SDL_SetTextureBlendMode(optTex, SDL_BLENDMODE_BLEND);
break;
case MENU_RECT_HEIGHT:
rH = newVal;
SDL_DestroyTexture(optTex);
optTex = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, rW, rH);
SDL_SetTextureBlendMode(optTex, SDL_BLENDMODE_BLEND);
break;
case MENU_FONT_SIZE:
@ -222,10 +228,11 @@ void ui::menu::draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText
if(tY < -rH || tY > tH)
continue;
gfx::clearTarget(optTex, &ui::transparent);
//Todo: Clean this up maybe
if(i == selected && drawText)
{
gfx::clearTarget(optTex, &ui::transparent);
if(isActive)
ui::drawBoundBox(target, x, y + (i * rH), rW, rH, clrSh);
@ -235,7 +242,11 @@ void ui::menu::draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText
if(hover && opt[i].txtWidth > rW - 24)
{
if((dX -= 2) <= -(opt[i].txtWidth + spcWidth))
{
dX = 0;
hoverCount = 0;
hover = false;
}
gfx::drawTextf(optTex, fSize, dX, ((rH - 8) / 2) - fSize / 2, ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, opt[i].txt.c_str());
gfx::drawTextf(optTex, fSize, dX + opt[i].txtWidth + spcWidth, ((rH - 8) / 2) - fSize / 2, ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, opt[i].txt.c_str());
@ -245,7 +256,6 @@ void ui::menu::draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText
dX = 0;
gfx::drawTextf(optTex, fSize, 0, ((rH - 8) / 2) - fSize / 2, ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, opt[i].txt.c_str());
}
gfx::texDraw(target, optTex, x + 20, (y + 4 + (i * rH)));
}
else if(i == selected && !drawText && opt[i].icn)
@ -258,8 +268,9 @@ void ui::menu::draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText
if(isActive)
ui::drawBoundBox(target, x, y + (i * rH), rW, rH, clrSh);
gfx::texDrawStretch(target, opt[i].icn, x + 20, (y + (rH / 2 - fSize / 2)) + (i * rH), dW, dH);
gfx::drawRect(target, ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, x + 10, ((y + (rH / 2 - fSize / 2)) + (i * rH)) - 2, 4, fSize + 4);
gfx::texDrawStretch(optTex, opt[i].icn, 0, ((rH - 8) / 2) - fSize / 2, dW, dH);
gfx::texDraw(target, optTex, x + 20, (y + 4 + (i * rH)));
}
else if(drawText)
{
@ -274,7 +285,8 @@ void ui::menu::draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText
float scale = (float)fSize / (float)h;
int dW = scale * w;
int dH = scale * h;
gfx::texDrawStretch(target, opt[i].icn, x + 20, (y + (rH / 2 - fSize / 2)) + (i * rH), dW, dH);
gfx::texDrawStretch(optTex, opt[i].icn, 0, ((rH - 8) / 2) - fSize / 2, dW, dH);
gfx::texDraw(target, optTex, x + 20, (y + 4 + (i * rH)));
}
}
}
@ -340,8 +352,16 @@ void ui::popMessageMngr::update()
void ui::popMessageMngr::popMessageAdd(const std::string& mess, int frameTime)
{
ui::popMessage newPop = {mess, 0, frameTime};
popQueue.push_back(newPop);
//Suppress multiple of the same
int lastMessageIndex = message.size() - 1;
std::string lastMessage;
if(lastMessageIndex >= 0)
lastMessage = message[lastMessageIndex].message;
if(lastMessage != mess)
{
ui::popMessage newPop = {mess, 0, frameTime};
popQueue.push_back(newPop);
}
}
void ui::popMessageMngr::draw()
@ -421,18 +441,18 @@ void confirmDrawFunc(void *a)
ui::confirmArgs *c = (ui::confirmArgs *)t->argPtr;
if(!t->finished)
{
std::string yesTxt = ui::yt;
std::string yesTxt = ui::getUIString("dialogYes", 0);
unsigned yesX = 0;
if((ui::padKeysHeld() & HidNpadButton_A) && c->hold)
{
c->frameCount++;
if(c->frameCount <= 40)
yesTxt = ui::holdingText[0];
yesTxt = ui::getUIString("holdingText", 0);
else if(c->frameCount <= 80)
yesTxt = ui::holdingText[1];
yesTxt = ui::getUIString("holdingText", 1);
else if(c->frameCount <= 120)
yesTxt = ui::holdingText[2];
yesTxt = ui::getUICString("holdingText", 2);
yesTxt += ui::loadGlyphArray[c->lgFrame];
}
@ -447,7 +467,7 @@ void confirmDrawFunc(void *a)
gfx::drawLine(NULL, &ui::rectSh, 280, 454, 999, 454);
gfx::drawLine(NULL, &ui::rectSh, 640, 454, 640, 518);
gfx::drawTextf(NULL, 18, yesX, 478, &ui::txtCont, yesTxt.c_str());
gfx::drawTextf(NULL, 18, 782, 478, &ui::txtCont, ui::nt.c_str());
gfx::drawTextf(NULL, 18, 782, 478, &ui::txtCont, ui::getUICString("dialogNo", 0));
}
}

View File

@ -9,11 +9,14 @@
ui::menu *ui::settMenu;
//This is the name of strings used here
static const char *settMenuStr = "settingsMenu";
static unsigned optHelpX = 0;
static inline std::string getBoolText(const bool& b)
{
return b ? ui::on : ui::off;
return b ? ui::getUIString("settingsOn", 0) : ui::getUIString("settingsOff", 0);
}
static inline void toggleBool(bool& b)
@ -58,9 +61,12 @@ static void toggleOpt(void *a)
case 2:
{
std::string oldWD = fs::getWorkDir();
std::string getWD = util::getStringInput(SwkbdType_QWERTY, fs::getWorkDir(), "Enter a new Output Path", 64, 0, NULL);
std::string getWD = util::getStringInput(SwkbdType_QWERTY, fs::getWorkDir(), ui::getUIString("swkbdSetWorkDir", 0), 64, 0, NULL);
if(!getWD.empty())
{
if(getWD[getWD.length() - 1] != '/')
getWD += "/";
rename(oldWD.c_str(), getWD.c_str());
fs::setWorkDir(getWD);
}
@ -136,24 +142,24 @@ static void toggleOpt(void *a)
static void updateMenuText()
{
ui::settMenu->editOpt(3, NULL, ui::optMenuStr[3] + getBoolText(cfg::config["incDev"]));
ui::settMenu->editOpt(4, NULL, ui::optMenuStr[4] + getBoolText(cfg::config["autoBack"]));
ui::settMenu->editOpt(5, NULL, ui::optMenuStr[5] + getBoolText(cfg::config["ovrClk"]));
ui::settMenu->editOpt(6, NULL, ui::optMenuStr[6] + getBoolText(cfg::config["holdDel"]));
ui::settMenu->editOpt(7, NULL, ui::optMenuStr[7] + getBoolText(cfg::config["holdRest"]));
ui::settMenu->editOpt(8, NULL, ui::optMenuStr[8] + getBoolText(cfg::config["holdOver"]));
ui::settMenu->editOpt(9, NULL, ui::optMenuStr[9] + getBoolText(cfg::config["forceMount"]));
ui::settMenu->editOpt(10, NULL, ui::optMenuStr[10] + getBoolText(cfg::config["accSysSave"]));
ui::settMenu->editOpt(11, NULL, ui::optMenuStr[11] + getBoolText(cfg::config["sysSaveWrite"]));
ui::settMenu->editOpt(12, NULL, ui::optMenuStr[12] + getBoolText(cfg::config["directFsCmd"]));
ui::settMenu->editOpt(13, NULL, ui::optMenuStr[13] + getBoolText(cfg::config["zip"]));
ui::settMenu->editOpt(14, NULL, ui::optMenuStr[14] + getBoolText(cfg::config["langOverride"]));
ui::settMenu->editOpt(15, NULL, ui::optMenuStr[15] + getBoolText(cfg::config["trashBin"]));
ui::settMenu->editOpt(16, NULL, ui::optMenuStr[16] + ui::sortString[cfg::sortType]);
ui::settMenu->editOpt(3, NULL, ui::getUIString(settMenuStr, 3) + getBoolText(cfg::config["incDev"]));
ui::settMenu->editOpt(4, NULL, ui::getUIString(settMenuStr, 4) + getBoolText(cfg::config["autoBack"]));
ui::settMenu->editOpt(5, NULL, ui::getUIString(settMenuStr, 5) + getBoolText(cfg::config["ovrClk"]));
ui::settMenu->editOpt(6, NULL, ui::getUIString(settMenuStr, 6) + getBoolText(cfg::config["holdDel"]));
ui::settMenu->editOpt(7, NULL, ui::getUIString(settMenuStr, 7) + getBoolText(cfg::config["holdRest"]));
ui::settMenu->editOpt(8, NULL, ui::getUIString(settMenuStr, 8) + getBoolText(cfg::config["holdOver"]));
ui::settMenu->editOpt(9, NULL, ui::getUIString(settMenuStr, 9) + getBoolText(cfg::config["forceMount"]));
ui::settMenu->editOpt(10, NULL, ui::getUIString(settMenuStr, 10) + getBoolText(cfg::config["accSysSave"]));
ui::settMenu->editOpt(11, NULL, ui::getUIString(settMenuStr, 11) + getBoolText(cfg::config["sysSaveWrite"]));
ui::settMenu->editOpt(12, NULL, ui::getUIString(settMenuStr, 12) + getBoolText(cfg::config["directFsCmd"]));
ui::settMenu->editOpt(13, NULL, ui::getUIString(settMenuStr, 13) + getBoolText(cfg::config["zip"]));
ui::settMenu->editOpt(14, NULL, ui::getUIString(settMenuStr, 14) + getBoolText(cfg::config["langOverride"]));
ui::settMenu->editOpt(15, NULL, ui::getUIString(settMenuStr, 15) + getBoolText(cfg::config["trashBin"]));
ui::settMenu->editOpt(16, NULL, ui::getUIString(settMenuStr, 16) + ui::getUICString("sortType", cfg::sortType));
char tmp[16];
sprintf(tmp, "%.1f", ui::animScale);
ui::settMenu->editOpt(17, NULL, ui::optMenuStr[17] + std::string(tmp));
ui::settMenu->editOpt(17, NULL, ui::getUIString(settMenuStr, 17) + std::string(tmp));
}
void ui::settInit()
@ -162,11 +168,11 @@ void ui::settInit()
ui::settMenu->setCallback(settMenuCallback, NULL);
ui::settMenu->setActive(false);
optHelpX = 1220 - gfx::getTextWidth(ui::optHelp.c_str(), 18);
optHelpX = 1220 - gfx::getTextWidth(ui::getUICString("helpSettings", 0), 18);
for(unsigned i = 0; i < 18; i++)
{
ui::settMenu->addOpt(NULL, ui::optMenuStr[i]);
ui::settMenu->addOpt(NULL, ui::getUIString("settingsMenu", i));
ui::settMenu->optAddButtonEvent(i, HidNpadButton_A, toggleOpt, NULL);
}
}
@ -186,5 +192,5 @@ void ui::settDraw(SDL_Texture *target)
updateMenuText();
ui::settMenu->draw(target, &ui::txtCont, true);
if(ui::mstate == OPT_MNU)
gfx::drawTextf(NULL, 18, optHelpX, 673, &ui::txtCont, ui::optHelp.c_str());
gfx::drawTextf(NULL, 18, optHelpX, 673, &ui::txtCont, ui::getUICString("helpSettings", 0));
}

View File

@ -31,7 +31,7 @@ static void fldFuncOverwrite(void *a)
int sel = m->getSelected() - 1;//Skip 'New'
std::string itm = d->getItem(sel);
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fs::overwriteBackup, a, true, ui::confOverwrite.c_str(), itm.c_str());
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fs::overwriteBackup, a, true, ui::getUICString("confirmOverwrite", 0), itm.c_str());
ui::confirm(conf);
}
@ -44,7 +44,7 @@ static void fldFuncDelete(void *a)
int sel = m->getSelected() - 1;//Skip 'New'
std::string itm = d->getItem(sel);
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fs::deleteBackup, a, true, ui::confDel.c_str(), itm.c_str());
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fs::deleteBackup, a, true, ui::getUICString("confirmDelete", 0), itm.c_str());
ui::confirm(conf);
}
@ -57,7 +57,7 @@ static void fldFuncRestore(void *a)
int sel = m->getSelected() - 1;//Skip 'New'
std::string itm = d->getItem(sel);
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdRest"], fs::restoreBackup, a, true, ui::confRestore.c_str(), itm.c_str());
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdRest"], fs::restoreBackup, a, true, ui::getUICString("confirmRestore", 0), itm.c_str());
ui::confirm(conf);
}
@ -65,13 +65,14 @@ void ui::populateFldMenu()
{
fldMenu->reset();
util::createTitleDirectoryByTID(data::curData.saveID);
std::string targetDir = util::generatePathByTID(data::curData.saveID);
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
util::createTitleDirectoryByTID(d->saveID);
std::string targetDir = util::generatePathByTID(d->saveID);
fldList->reassign(targetDir);
char filterPath[128];
sprintf(filterPath, "sdmc:/config/JKSV/0x%016lX_filter.txt", data::curData.saveID);
sprintf(filterPath, "sdmc:/config/JKSV/0x%016lX_filter.txt", d->saveID);
fs::loadPathFilters(filterPath);
*backargs = {fldMenu, fldList};
@ -93,34 +94,37 @@ void ui::populateFldMenu()
static void ttlViewCallback(void *a)
{
data::selData = ttlViews[data::selUser]->getSelected();
unsigned curUserIndex = data::getCurrentUserIndex();
unsigned setUserTitleIndex = ttlViews[curUserIndex]->getSelected();
data::setTitleIndex(setUserTitleIndex);
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
switch(ui::padKeysDown())
{
case HidNpadButton_A:
if(fs::mountSave(data::curData.saveInfo))
if(fs::mountSave(d->saveInfo))
ui::populateFldMenu();
break;
case HidNpadButton_B:
ttlViews[data::selUser]->setActive(false, false);
ttlViews[curUserIndex]->setActive(false, false);
ui::usrMenu->setActive(true);
ui::changeState(USR_SEL);
break;
case HidNpadButton_X:
data::selData = ttlViews[data::selUser]->getSelected();
ttlViews[data::selUser]->setActive(false, true);
data::setTitleIndex(ttlViews[curUserIndex]->getSelected());
ttlViews[curUserIndex]->setActive(false, true);
ttlOpts->setActive(true);
ui::ttlOptsPanel->openPanel();
break;
case HidNpadButton_Y:
{
uint64_t sid = data::curData.saveID;
cfg::addTitleToFavorites(sid);
int newSel = data::getTitleIndexInUser(data::curUser, sid);
cfg::addTitleToFavorites(d->saveID);
int newSel = data::getTitleIndexInUser(*data::getCurrentUser(), d->saveID);
ui::ttlRefresh();
ttlViews[data::selUser]->setSelected(newSel);
ttlViews[curUserIndex]->setSelected(newSel);
}
break;
}
@ -131,10 +135,13 @@ static void ttlOptsCallback(void *a)
switch(ui::padKeysDown())
{
case HidNpadButton_B:
ttlOpts->setActive(false);
ui::ttlOptsPanel->closePanel();
ttlViews[data::selUser]->setActive(true, true);
ui::updateInput();
{
int curUserIndex = data::getCurrentUserIndex();
ttlOpts->setActive(false);
ui::ttlOptsPanel->closePanel();
ttlViews[curUserIndex]->setActive(true, true);
ui::updateInput();
}
break;
}
}
@ -149,20 +156,20 @@ static void ttlOptsShowInfoPanel(void *a)
{
ttlOpts->setActive(false);
ui::ttlOptsPanel->closePanel();
infoPanelString = util::getInfoString(data::curUser, data::curData.saveID);
infoPanelString = util::getInfoString(*data::getCurrentUser(), data::getCurrentUserTitleInfo()->saveID);
infoPanel->openPanel();
}
static void ttlOptsBlacklistTitle(void *a)
{
std::string title = data::getTitleNameByTID(data::curData.saveID);
ui::confirmArgs *conf = ui::confirmArgsCreate(false, cfg::addTitleToBlacklist, NULL, true, ui::confBlacklist.c_str(), title.c_str());
std::string title = data::getTitleNameByTID(data::getCurrentUserTitleInfo()->saveID);
ui::confirmArgs *conf = ui::confirmArgsCreate(false, cfg::addTitleToBlacklist, NULL, true, ui::getUICString("confirmBlacklist", 0), title.c_str());
ui::confirm(conf);
}
static void ttlOptsDefinePath(void *a)
{
uint64_t tid = data::curData.saveID;
uint64_t tid = data::getCurrentUserTitleInfo()->saveID;
std::string safeTitle = data::getTitleInfoByTID(tid)->safeTitle;
std::string newSafeTitle = util::getStringInput(SwkbdType_QWERTY, safeTitle, "Input New Output Folder", 0x200, 0, NULL);
if(!newSafeTitle.empty())
@ -171,9 +178,10 @@ static void ttlOptsDefinePath(void *a)
static void ttlOptsToFileMode(void *a)
{
if(fs::mountSave(data::curData.saveInfo))
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
if(fs::mountSave(d->saveInfo))
{
ui::fmPrep((FsSaveDataType)data::curData.saveInfo.save_data_type, "sv:/", true);
ui::fmPrep((FsSaveDataType)d->saveInfo.save_data_type, "sv:/", true);
ui::usrSelPanel->closePanel();
ui::ttlOptsPanel->closePanel();
ui::changeState(FIL_MDE);
@ -183,23 +191,25 @@ static void ttlOptsToFileMode(void *a)
static void ttlOptsResetSaveData_t(void *a)
{
threadInfo *t = (threadInfo *)a;
std::string title = data::getTitleNameByTID(data::curData.saveID);
t->status->setStatus("Resetting save data for " + title + "...");
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
std::string title = data::getTitleNameByTID(d->saveID);
t->status->setStatus(ui::getUICString("threadStatusResettingSaveData", 0), title.c_str());
fs::mountSave(data::curData.saveInfo);
fs::mountSave(d->saveInfo);
fs::delDir("sv:/");
fsdevCommitDevice("sv:/");
fs::unmountSave();
ui::showPopMessage(POP_FRAME_DEFAULT, ui::saveDataResetSuccess.c_str(), title.c_str());
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataResetSuccess", 0), title.c_str());
t->finished = true;
}
static void ttlOptsResetSaveData(void *a)
{
if(data::curData.saveInfo.save_data_type != FsSaveDataType_System)
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
if(d->saveInfo.save_data_type != FsSaveDataType_System)
{
std::string title = data::getTitleNameByTID(data::curData.saveID);
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsResetSaveData_t, NULL, true, ui::saveDataReset.c_str(), title.c_str());
std::string title = data::getTitleNameByTID(d->saveID);
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsResetSaveData_t, NULL, true, ui::getUICString("confirmResetSaveData", 0), title.c_str());
ui::confirm(conf);
}
}
@ -207,47 +217,54 @@ static void ttlOptsResetSaveData(void *a)
static void ttlOptsDeleteSaveData_t(void *a)
{
threadInfo *t = (threadInfo *)a;
std::string title = data::getTitleNameByTID(data::curData.saveID);
t->status->setStatus("Deleting save data for " + title + "...");
if(R_SUCCEEDED(fsDeleteSaveDataFileSystemBySaveDataSpaceId((FsSaveDataSpaceId)data::curData.saveInfo.save_data_space_id, data::curData.saveInfo.save_data_id)))
data::user *u = data::getCurrentUser();
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
unsigned userIndex = data::getCurrentUserIndex();
std::string title = data::getTitleNameByTID(d->saveID);
t->status->setStatus(ui::getUICString("threadStatusDeletingSaveData", 0), title.c_str());
if(R_SUCCEEDED(fsDeleteSaveDataFileSystemBySaveDataSpaceId((FsSaveDataSpaceId)d->saveInfo.save_data_space_id, d->saveInfo.save_data_id)))
{
data::loadUsersTitles(false);
if(data::curUser.titleInfo.size() == 0)
if(u->titleInfo.size() == 0)
{
//Kick back to user
ui::ttlOptsPanel->closePanel();//JIC
ttlOpts->setActive(false);
ttlViews[data::selUser]->setActive(false, false);
ttlViews[userIndex]->setActive(false, false);
ui::usrMenu->setActive(true);
ui::changeState(USR_SEL);
}
ui::showPopMessage(POP_FRAME_DEFAULT, ui::saveDataDeleteSuccess.c_str(), title.c_str());
ttlViews[data::selUser]->refresh();
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataDeleteSuccess", 0), title.c_str());
ttlViews[userIndex]->refresh();
}
t->finished = true;
}
static void ttlOptsDeleteSaveData(void *a)
{
if(data::curData.saveInfo.save_data_type != FsSaveDataType_System)
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
if(d->saveInfo.save_data_type != FsSaveDataType_System)
{
std::string title = data::getTitleNameByTID(data::curData.saveID);
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsDeleteSaveData_t, NULL, true, ui::confEraseNand.c_str(), title.c_str());
std::string title = data::getTitleNameByTID(d->saveID);
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsDeleteSaveData_t, NULL, true, ui::getUICString("confirmDeleteSaveData", 0), title.c_str());
ui::confirm(conf);
}
}
static void ttlOptsExtendSaveData_t(void *a)
{
threadInfo *w = (threadInfo *)a;
threadInfo *t = (threadInfo *)a;
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
std::string expSizeStr = util::getStringInput(SwkbdType_NumPad, "", "Enter New Size in MB", 4, 0, NULL);
if(!expSizeStr.empty())
{
int64_t journ = 0, expSize;
data::titleInfo *extend = data::getTitleInfoByTID(data::curData.saveID);
w->status->setStatus("Expanding save filesystem for " + extend->title);
data::titleInfo *extend = data::getTitleInfoByTID(d->saveID);
t->status->setStatus(ui::getUICString("threadStatusExtendingSaveData", 0), extend->title.c_str());
//Get journal size
switch(data::curData.saveInfo.save_data_type)
switch(d->saveInfo.save_data_type)
{
case FsSaveDataType_Account:
if(extend->nacp.user_account_save_data_journal_size_max > extend->nacp.user_account_save_data_journal_size)
@ -281,33 +298,37 @@ static void ttlOptsExtendSaveData_t(void *a)
}
uint64_t expMB = strtoul(expSizeStr.c_str(), NULL, 10);
expSize = expMB * 0x100000;
FsSaveDataSpaceId space = (FsSaveDataSpaceId)data::curData.saveInfo.save_data_space_id;
uint64_t sid = data::curData.saveInfo.save_data_id;
FsSaveDataSpaceId space = (FsSaveDataSpaceId)d->saveInfo.save_data_space_id;
uint64_t sid = d->saveInfo.save_data_id;
Result res = 0;
if(R_FAILED(res = fsExtendSaveDataFileSystem(space, sid, expSize, journ)))
{
int64_t totalSize = 0;
fs::mountSave(data::curData.saveInfo);
fs::mountSave(d->saveInfo);
fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &totalSize);
fs::unmountSave();
fs::logWrite("Extend Failed: %uMB to %uMB -> %X\n", totalSize / 1024 / 1024, expSize / 1024 / 1024, res);
ui::showPopMessage(POP_FRAME_DEFAULT, "Failed to expand save data.");
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataExtendFailed", 0));
}
else
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataExtendSuccess", 0), extend->title.c_str());
}
w->finished = true;
t->finished = true;
}
static void ttlOptsExtendSaveData(void *a)
{
if(data::curData.saveInfo.save_data_type != FsSaveDataType_System)
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
if(d->saveInfo.save_data_type != FsSaveDataType_System)
ui::newThread(ttlOptsExtendSaveData_t, NULL, NULL);
}
static void infoPanelDraw(void *a)
{
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
SDL_Texture *panel = (SDL_Texture *)a;
gfx::texDraw(panel, data::getTitleIconByTID(data::curData.saveID), 77, 32);
gfx::texDraw(panel, data::getTitleIconByTID(d->saveID), 77, 32);
gfx::drawTextfWrap(panel, 18, 32, 320, 362, &ui::txtCont, infoPanelString.c_str());
}
@ -345,13 +366,13 @@ static void fldPanelDraw(void *a)
fldMenu->draw(fldBuffer, &ui::txtCont, true);
gfx::texDraw(target, fldBuffer, 0, 0);
gfx::drawLine(target, &ui::divClr, 10, 648, fldHelpWidth + 54, 648);
gfx::drawTextf(target, 18, 32, 673, &ui::txtCont, ui::folderHelp.c_str());
gfx::drawTextf(target, 18, 32, 673, &ui::txtCont, ui::getUICString("helpFolder", 0));
}
void ui::ttlInit()
{
ttlHelpX = 1220 - gfx::getTextWidth(ui::titleHelp.c_str(), 18);
fldHelpWidth = gfx::getTextWidth(ui::folderHelp.c_str(), 18);
ttlHelpX = 1220 - gfx::getTextWidth(ui::getUICString("helpTitle", 0), 18);
fldHelpWidth = gfx::getTextWidth(ui::getUICString("helpFolder", 0), 18);
for(data::user& u : data::users)
ttlViews.emplace_back(new ui::titleview(u, 128, 128, 16, 16, 7, ttlViewCallback));
@ -379,19 +400,22 @@ void ui::ttlInit()
backargs = new fs::backupArgs;
ttlOpts->setActive(false);
ttlOpts->addOpt(NULL, ui::titleOptString[0]);
for(int i = 0; i < 7; i++)
ttlOpts->addOpt(NULL, ui::getUIString("titleOptions", i));
//Information
ttlOpts->optAddButtonEvent(0, HidNpadButton_A, ttlOptsShowInfoPanel, NULL);
ttlOpts->addOpt(NULL, ui::titleOptString[1]);
//Blacklist
ttlOpts->optAddButtonEvent(1, HidNpadButton_A, ttlOptsBlacklistTitle, NULL);
ttlOpts->addOpt(NULL, ui::titleOptString[2]);
//Title Define
ttlOpts->optAddButtonEvent(2, HidNpadButton_A, ttlOptsDefinePath, NULL);
ttlOpts->addOpt(NULL, ui::titleOptString[3]);
//File Mode
ttlOpts->optAddButtonEvent(3, HidNpadButton_A, ttlOptsToFileMode, NULL);
ttlOpts->addOpt(NULL, ui::titleOptString[4]);
//Reset Save
ttlOpts->optAddButtonEvent(4, HidNpadButton_A, ttlOptsResetSaveData, NULL);
ttlOpts->addOpt(NULL, ui::titleOptString[5]);
//Delete Save
ttlOpts->optAddButtonEvent(5, HidNpadButton_A, ttlOptsDeleteSaveData, NULL);
ttlOpts->addOpt(NULL, ui::titleOptString[6]);
//Extend
ttlOpts->optAddButtonEvent(6, HidNpadButton_A, ttlOptsExtendSaveData, NULL);
}
@ -417,15 +441,19 @@ void ui::ttlSetActive(int usr)
void ui::ttlUpdate()
{
unsigned curUserIndex = data::getCurrentUserIndex();
ttlOpts->update();
infoPanel->update();
fldMenu->update();
ttlViews[data::selUser]->update();
ttlViews[curUserIndex]->update();
}
void ui::ttlDraw(SDL_Texture *target)
{
ttlViews[data::selUser]->draw(target);
unsigned curUserIndex = data::getCurrentUserIndex();
ttlViews[curUserIndex]->draw(target);
if(ui::mstate == TTL_SEL && !fldPanel->isOpen())
gfx::drawTextf(NULL, 18, ttlHelpX, 673, &ui::txtCont, ui::titleHelp.c_str());
gfx::drawTextf(NULL, 18, ttlHelpX, 673, &ui::txtCont, ui::getUICString("helpTitle", 0));
}

View File

@ -1,217 +1,197 @@
#include <string>
#include <unordered_map>
#include <map>
#include "file.h"
#include "cfg.h"
#include "type.h"
#include "uistr.h"
//Map to associate external string names to unsigned ints for switch case.
static std::unordered_map<std::string, unsigned> uistrdef =
{
{"author", 0}, {"userHelp", 1}, {"titleHelp", 2}, {"folderHelp", 3}, {"optHelp", 4},
{"yt", 5}, {"nt", 6}, {"on", 7}, {"off", 8}, {"confirmBlacklist", 9}, {"confirmOverwrite", 10},
{"confirmRestore", 11}, {"confirmDelete", 12}, {"confirmCopy", 13}, {"confirmEraseNand", 14},
{"confirmReset", 15}, {"confirmHead", 16}, {"copyHead", 17}, {"noSavesFound", 18},
{"advMenu", 19}, {"extMenu", 20}, {"optMenu", 21}, {"optMenuExp", 22}, {"holdingText", 23},
{"errorConnecting", 24}, {"noUpdate", 25}, {"sortType", 26}, {"saveCreated", 27}, {"saveCreateFailed", 28},
{"saveDataResetSuccess", 29}, {"saveDataDeleteSuccess", 30}
};
std::map<std::pair<std::string, int>, std::string> ui::strings;
std::string ui::author = "NULL";
std::string ui::userHelp = "[A] Select [X] User Options";
std::string ui::titleHelp = "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back";
std::string ui::folderHelp = "[A] Select [Y] Restore [X] Delete [B] Close";
std::string ui::optHelp = "[A] Toggle [X] Defaults [B] Back";
std::string ui::yt = "Yes [A]", ui::nt = "No [B]";
std::string ui::on = ">On>", ui::off = "Off";
std::string ui::confBlacklist = "Are you sure you want to add #%s# to your blacklist?";
std::string ui::confOverwrite = "Are you sure you want to overwrite #%s#?";
std::string ui::confRestore = "Are you sure you want to restore #%s#?";
std::string ui::confDel = "Are you sure you want to delete #%s#? *This is permanent*!";
std::string ui::confCopy = "Are you sure you want to copy #%s# to #%s#?";
std::string ui::confirmHead = "Confirm";
std::string ui::copyHead = "Copying File...";
std::string ui::confEraseNand = "*WARNING*: This *will* erase the save data for #%s# *from your system*. This is the same as deleting it from #Data Management#! Are you sure you want to continue?";
std::string ui::noSavesFound = "No saves found for #%s#!";
std::string ui::saveCreated = "Save data created for %s!";
std::string ui::saveCreateFailed = "Save data creation failed!";
std::string ui::saveDataReset = "Are you sure want to reset your current save data for %s?";
std::string ui::saveDataResetSuccess = "Save for %s reset!";
std::string ui::saveDataDeleteSuccess = "Save data for %s deleted!";
std::string ui::errorConnecting = "Error Connecting!";
std::string ui::noUpdate = "No updates available!";
std::string ui::advMenuStr[7] = { "Copy to ", "Delete", "Rename", "Make Dir", "Properties", "Close", "Add to Path Filter" };
std::string ui::exMenuStr[11] = { "SD to SD Browser", "BIS: PRODINFOF", "BIS: SAFE", "BIS: SYSTEM", "BIS: USER", "Remove Update", "Terminate Process", "Mount System Save", "Rescan Titles", "Mount Process RomFS", "Backup JKSV Folder" };
std::string ui::optMenuStr[18] = { "Empty Trash Bin", "Check for Update", "Set Output Folder", "Include Device Saves: ", "AutoBackup: ", "Overclock: ", "Hold to Delete: ", "Hold to Restore: ", "Hold to Overwrite: ", "Force Mount: ", "Account Sys. Saves: ", "Write to Sys. Saves: ", "Direct FS Cmd: ", "Export to ZIP: ", "Language Override: ", "Enable Trash Bin: ", "Sort: ", "Animation Scale: "};
std::string ui::holdingText[3] = { "(Hold) ", "(Keep Holding) ", "(Almost there!) " };
std::string ui::sortString[3] = { "Alphabetical", "Time Played", "Last Played" };
std::string ui::usrOptString[2] = { "Create Save Data", "Delete All User Saves" };
std::string ui::titleOptString[7] = {"Information", "Blacklist", "Change Output folder", "Open in File Mode", "Reset Save Data", "Delete Save Filesystem", "Extend Save Filesystem"};
static inline void addUIString(const std::string& _name, int ind, const std::string& _str)
{
ui::strings[std::make_pair(_name, ind)] = _str;
}
void ui::initStrings()
{
addUIString("author", 0, "NULL");
addUIString("helpUser", 0, "[A] Select [X] User Options");
addUIString("helpTitle", 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back");
addUIString("helpFolder", 0, "[A] Select [Y] Restore [X] Delete [B] Close");
addUIString("helpSettings", 0, "[A] Toggle [X] Defaults [B] Back");
//Y/N On/Off
addUIString("dialogYes", 0, "Yes [A]");
addUIString("dialogNo", 0, "No [B]");
addUIString("settingsOn", 0, ">On>");
addUIString("settingsOff", 0, "Off");
addUIString("holdingText", 0, "(Hold) ");
addUIString("holdingText", 1, "(Keep Holding) ");
addUIString("holdingText", 2, "(Almost There!) ");
//Confirmation Strings
addUIString("confirmBlacklist", 0, "Are you sure you want to add #%s# to your blacklist?");
addUIString("confirmOverwrite", 0, "Are you sure you want to overwrite #%s#?");
addUIString("confirmRestore", 0, "Are you sure you want to restore #%s#?");
addUIString("confirmDelete", 0, "Are you sure you want to delete #%s#? *This is permanent*!");
addUIString("confirmCopy", 0, "Are you sure you want to copy #%s# to #%s#?");
addUIString("confirmDeleteSaveData", 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?");
addUIString("confirmResetSaveData", 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?");
//Save Data related strings
addUIString("saveDataNoneFound", 0, "No saves found for #%s#!");
addUIString("saveDataCreatedForUser", 0, "Save data created for %s!");
addUIString("saveDataCreationFailed", 0, "Save data creation failed!");
addUIString("saveDataResetSuccess", 0, "Save for #%s# reset!");
addUIString("saveDataDeleteSuccess", 0, "Save data for #%s# deleted!");
addUIString("saveDataExtendSuccess", 0, "Save data for #%s# extended!");
addUIString("saveDataExtendFailed", 0, "Failed to extend save data.");
addUIString("saveDataDeleteAllUser", 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %s?*");
addUIString("saveDataBackupDeleted", 0, "#%s# has been deleted.");
addUIString("saveDataBackupMovedToTrash", 0, "#%s# has been moved to trash.");
//Internet Related
addUIString("onlineErrorConnecting", 0, "Error Connecting!");
addUIString("onlineNoUpdates", 0, "No Updates Available.");
//File mode menu strings
addUIString("fileModeMenu", 0, "Copy To ");
addUIString("fileModeMenu", 1, "Delete");
addUIString("fileModeMenu", 2, "Rename");
addUIString("fileModeMenu", 3, "Make Dir");
addUIString("fileModeMenu", 4, "Properties");
addUIString("fileModeMenu", 5, "Close");
addUIString("fileModeMenu", 6, "Add to Path Filters");
//Settings menu
addUIString("settingsMenu", 0, "Empty Trash Bin");
addUIString("settingsMenu", 1, "Check for Updates");
addUIString("settingsMenu", 2, "Set JKSV Save Output Folder");
addUIString("settingsMenu", 3, "Include Device Saves With Users: ");
addUIString("settingsMenu", 4, "Auto Backup On Restore: ");
addUIString("settingsMenu", 5, "Overclock/CPU Boost: ");
addUIString("settingsMenu", 6, "Hold To Delete: ");
addUIString("settingsMenu", 7, "Hold To Restore: ");
addUIString("settingsMenu", 8, "Hold To Overwrite: ");
addUIString("settingsMenu", 9, "Force Mount: ");
addUIString("settingsMenu", 10, "Account System Saves: ");
addUIString("settingsMenu", 11, "Enable Writing to System Saves: ");
addUIString("settingsMenu", 12, "Use FS Commands Directly: ");
addUIString("settingsMenu", 13, "Export Saves to ZIP: ");
addUIString("settingsMenu", 14, "Force English To Be Used: ");
addUIString("settingsMenu", 15, "Enable Trash Bin: ");
addUIString("settingsMenu", 16, "Title Sorting Type: ");
addUIString("settingsMenu", 17, "Animation Scale: ");
//Sort Strings for ^
addUIString("sortType", 0, "Alphabetical");
addUIString("sortType", 1, "Time Played");
addUIString("sortType", 2, "Last Played");
//Extras
addUIString("extrasMenu", 0, "SD to SD Browser");
addUIString("extrasMenu", 1, "BIS: ProdInfoF");
addUIString("extrasMenu", 2, "BIS: Safe");
addUIString("extrasMenu", 3, "BIS: System");
addUIString("extrasMenu", 4, "BIS: User");
addUIString("extrasMenu", 5, "Remove Pending Update");
addUIString("extrasMenu", 6, "Terminate Process");
addUIString("extrasMenu", 7, "Mount System Save");
addUIString("extrasMenu", 8, "Rescan Titles");
addUIString("extrasMenu", 9, "Mount Process RomFS");
addUIString("extrasMenu", 10, "Backup JKSV Folder");
addUIString("extrasMenu", 11, "*[DEV]* Output en-US");
//User Options
addUIString("userOptions", 0, "Create Save Data");
addUIString("userOptions", 1, "Create All Save Data");
addUIString("userOptions", 2, "Delete All User Saves");
//Title Options
addUIString("titleOptions", 0, "Information");
addUIString("titleOptions", 1, "Blacklist");
addUIString("titleOptions", 2, "Change Output Folder");
addUIString("titleOptions", 3, "Open in File Mode");
addUIString("titleOptions", 4, "Reset Save Data");
addUIString("titleOptions", 5, "Delete Save Data");
addUIString("titleOptions", 6, "Extend Save Data");
//Thread Status Strings
addUIString("threadStatusCreatingSaveData", 0, "Creating save data for #%s#...");
addUIString("threadStatusCopyingFile", 0, "Copying '#%s#'...");
addUIString("threadStatusDeletingFile", 0, "Deleting...");
addUIString("threadStatusOpeningFolder", 0, "Opening '#%s#'...");
addUIString("threadStatusAddingFileToZip", 0, "Adding '#%s#' to ZIP...");
addUIString("threadStatusDecompressingFile", 0, "Decompressing '#%s#'...");
addUIString("threadStatusResettingSaveData", 0, "Resetting Save Data for #%s#...");
addUIString("threadStatusDeletingSaveData", 0, "Deleting Save Data for #%s#...");
addUIString("threadStatusExtendingSaveData", 0, "Extending Save Data for #%s#...");
addUIString("threadStatusCreatingSaveData", 0, "Creating Save Data for #%s#...");
addUIString("threadStatusResettingSaveData", 0, "Resetting save data...");
addUIString("threadStatusDeletingUpdate", 0, "Deleting pending update...");
addUIString("threadStatusCheckingForUpdate", 0, "Checking for updates...");
addUIString("threadStatusDownloadingUpdate", 0, "Downloading update...");
//Random leftover pop-ups
addUIString("popCPUBoostEnabled", 0, "CPU Boost Enabled for ZIP.");
addUIString("popErrorCommittingFile", 0, "Error committing file to save!");
addUIString("popProcessShutdown", 0, "#%s# successfully shutdown.");
addUIString("popAddedToPathFilter", 0, "'#%s#' added to path filters.");
//Keyboard hints
addUIString("swkbdEnterName", 0, "Enter a new name");
addUIString("swkbdSaveIndex", 0, "Enter Cache Index");
addUIString("swkbdSetWorkDir", 0, "Enter a new Output Path");
addUIString("swkbdProcessID", 0, "Enter Process ID");
addUIString("swkbdSysSavID", 0, "Enter System Save ID");
addUIString("swkbdRename", 0, "Enter a new name for item");
addUIString("swkbdMkDir", 0, "Enter a folder name");
}
void ui::loadTrans()
{
//Disable translation loading until new UI done
return;
bool transFile = fs::fileExists(fs::getWorkDir() + "trans.txt");
if(!transFile && (data::sysLang == SetLanguage_ENUS || cfg::config["langOverride"]))
return;//Don't bother loading from file. It serves as a translation guide
std::string file;
if(transFile)
file = fs::getWorkDir() + "trans.txt";
ui::initStrings();
else
{
file = "romfs:/lang/";
switch(data::sysLang)
std::string file;
if(transFile)
file = fs::getWorkDir() + "trans.txt";
else
{
case SetLanguage_ZHCN:
case SetLanguage_ZHHANS:
file += "zh-CN.txt";
break;
case SetLanguage_ZHTW:
case SetLanguage_ZHHANT:
file += "zh-TW.txt";
break;
default:
return;
break;
file = "romfs:/lang/";
switch(data::sysLang)
{
//I removed these for now. Old translation files are incompatible and will cause crashes.
default:
ui::initStrings();
return;
break;
}
}
}
fs::dataFile lang(file);
while(lang.readNextLine(true))
{
switch(uistrdef[lang.getName()])
fs::dataFile lang(file);
while(lang.readNextLine(true))
{
case 0:
ui::author = lang.getNextValueStr();
break;
case 1:
ui::userHelp = lang.getNextValueStr();
break;
case 2:
ui::titleHelp = lang.getNextValueStr();
break;
case 3:
ui::folderHelp = lang.getNextValueStr();
break;
case 4:
ui::optHelp = lang.getNextValueStr();
break;
case 5:
ui::yt = lang.getNextValueStr();
break;
case 6:
ui::nt = lang.getNextValueStr();
break;
case 7:
ui::on = lang.getNextValueStr();
break;
case 8:
ui::off = lang.getNextValueStr();
break;
case 9:
ui::confBlacklist = lang.getNextValueStr();
break;
case 10:
ui::confOverwrite = lang.getNextValueStr();
break;
case 11:
ui::confRestore = lang.getNextValueStr();
break;
case 12:
ui::confDel = lang.getNextValueStr();
break;
case 13:
ui::confCopy = lang.getNextValueStr();
break;
case 14:
ui::confEraseNand = lang.getNextValueStr();
break;
case 15:
ui::saveDataReset = lang.getNextValueStr();
break;
case 16:
ui::confirmHead = lang.getNextValueStr();
break;
case 17:
ui::copyHead = lang.getNextValueStr();
break;
case 18:
ui::noSavesFound = lang.getNextValueStr();
break;
case 19:
{
int ind = lang.getNextValueInt();
ui::advMenuStr[ind] = lang.getNextValueStr();
}
break;
case 20:
{
int ind = lang.getNextValueInt();
ui::exMenuStr[ind] = lang.getNextValueStr();
}
break;
case 21:
{
int ind = lang.getNextValueInt();
ui::optMenuStr[ind] = lang.getNextValueStr();
}
break;
case 22:
break;
case 23:
{
int ind = lang.getNextValueInt();
ui::holdingText[ind] = lang.getNextValueStr();
}
break;
case 24:
ui::errorConnecting = lang.getNextValueStr();
break;
case 25:
ui::noUpdate = lang.getNextValueStr();
break;
case 26:
{
int ind = lang.getNextValueInt();
ui::sortString[ind] = lang.getNextValueStr();
}
break;
default:
fs::logWrite("Translation File Error -> On Line: %s: '%s' is not a known or valid string name.\n", lang.getLine().c_str(), lang.getName().c_str());
break;
std::string name = lang.getName();
int ind = lang.getNextValueInt();
std::string str = lang.getNextValueStr();
addUIString(name, ind, str);
}
}
}
void ui::saveTranslationFile(void *a)
{
threadInfo *t = (threadInfo *)a;
t->status->setStatus("Saving the file master...");
std::string out = fs::getWorkDir() + "en-US.txt";
FILE *enUS = fopen(out.c_str(), "w");
for(auto& s : ui::strings)
fprintf(enUS, "%s = %i, \"%s\"\n", s.first.first.c_str(), s.first.second, s.second.c_str());
fclose(enUS);
t->finished = true;
}

View File

@ -25,15 +25,6 @@ static ui::slideOutPanel *usrOptPanel, *saveCreatePanel, *deviceSavePanel, *bcat
//Icons for settings + extras
static SDL_Texture *sett, *ext;
//Struct to send args to createFunc
typedef struct
{
FsSaveDataType type;
ui::menu *m;
} svCreateArgs;
static svCreateArgs accCreate, devCreate, bcatCreate, cacheCreate;
//This stores save ids to match with saveCreateMenu
//Probably needs/should be changed
static std::vector<uint64_t> accSids, devSids, bcatSids, cacheSids;
@ -67,7 +58,10 @@ static struct
static void onMainChange(void *a)
{
if(ui::usrMenu->getSelected() < (int)data::users.size())
data::selUser = ui::usrMenu->getSelected();
{
unsigned setUser = ui::usrMenu->getSelected();
data::setUserIndex(setUser);
}
}
static void _usrSelPanelDraw(void *a)
@ -168,15 +162,15 @@ static void usrOptSaveCreate(void *a)
static void usrOptDeleteAllUserSaves_t(void *a)
{
threadInfo *t = (threadInfo *)a;
data::user *u = &data::users[data::selUser];
data::user *u = data::getCurrentUser();
int curUserIndex = data::getCurrentUserIndex();
int devUser = ui::usrMenu->getOptPos("Device");
for(data::userTitleInfo& tinf : u->titleInfo)
{
if(tinf.saveInfo.save_data_type != FsSaveDataType_System && (tinf.saveInfo.save_data_type != FsSaveDataType_Device || data::selUser == devUser))
if(tinf.saveInfo.save_data_type != FsSaveDataType_System && (tinf.saveInfo.save_data_type != FsSaveDataType_Device || curUserIndex == devUser))
{
t->status->setStatus("Deleting " + data::getTitleNameByTID(tinf.saveID));
t->status->setStatus(ui::getUICString("threadStatusDeletingSaveData", 0), data::getTitleNameByTID(tinf.saveID).c_str());
fsDeleteSaveDataFileSystemBySaveDataSpaceId(FsSaveDataSpaceId_User, tinf.saveInfo.save_data_id);
}
}
@ -187,8 +181,8 @@ static void usrOptDeleteAllUserSaves_t(void *a)
static void usrOptDeleteAllUserSaves(void *a)
{
data::user *u = &data::users[data::selUser];
ui::confirmArgs *conf = ui::confirmArgsCreate(true, usrOptDeleteAllUserSaves_t, NULL, true, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %s?*", u->getUsername().c_str());
data::user *u = data::getCurrentUser();
ui::confirmArgs *conf = ui::confirmArgsCreate(true, usrOptDeleteAllUserSaves_t, NULL, true, ui::getUICString("saveDataDeleteAllUser", 0), u->getUsername().c_str());
ui::confirm(conf);
}
@ -222,117 +216,62 @@ static void cacheSavePanelDraw(void *a)
cacheSaveMenu->draw(panel, &ui::txtCont, true);
}
static void createSaveData_t(void *a)
{
threadInfo *t = (threadInfo *)a;
svCreateArgs *in = (svCreateArgs *)t->argPtr;
FsSaveDataType type = in->type;
ui::menu *m = in->m;
uint64_t sid;
switch(type)
{
case FsSaveDataType_Account:
sid = accSids[m->getSelected()];
break;
case FsSaveDataType_Device:
sid = devSids[m->getSelected()];
break;
case FsSaveDataType_Bcat:
sid = bcatSids[m->getSelected()];
break;
case FsSaveDataType_Cache:
sid = cacheSids[m->getSelected()];
break;
default:
return;
break;
}
data::titleInfo *create = data::getTitleInfoByTID(sid);
t->status->setStatus("Creating save data for " + create->title);
FsSaveDataAttribute attr;
memset(&attr, 0, sizeof(FsSaveDataAttribute));
attr.application_id = sid;
attr.uid = type == FsSaveDataType_Account ? data::curUser.getUID() : util::u128ToAccountUID(0);
attr.system_save_data_id = 0;
attr.save_data_type = type;
attr.save_data_rank = 0;
uint16_t index = 0;
if(type == FsSaveDataType_Cache)
{
std::string getIndex = util::getStringInput(SwkbdType_NumPad, "", "Input Cache save index", 2, 0, NULL);
index = strtoul(getIndex.c_str(), 0, 10);
}
attr.save_data_index = index;
FsSaveDataCreationInfo svCreate;
memset(&svCreate, 0, sizeof(FsSaveDataCreationInfo));
int64_t saveSize = 0, journalSize = 0;
switch(type)
{
case FsSaveDataType_Account:
saveSize = create->nacp.user_account_save_data_size;
journalSize = create->nacp.user_account_save_data_journal_size;
break;
case FsSaveDataType_Device:
saveSize = create->nacp.device_save_data_size;
journalSize = create->nacp.device_save_data_journal_size;
break;
case FsSaveDataType_Bcat:
saveSize = create->nacp.bcat_delivery_cache_storage_size;
journalSize = create->nacp.bcat_delivery_cache_storage_size;
break;
case FsSaveDataType_Cache:
saveSize = 32 * 1024 * 1024;//Todo: Add target folder/zip selection for size
if(create->nacp.cache_storage_journal_size > create->nacp.cache_storage_data_and_journal_size_max)
journalSize = create->nacp.cache_storage_journal_size;
else
journalSize = create->nacp.cache_storage_data_and_journal_size_max;
break;
default:
return;
break;
}
svCreate.save_data_size = saveSize;
svCreate.journal_size = journalSize;
svCreate.available_size = 0x4000;
svCreate.owner_id = create->nacp.save_data_owner_id;
svCreate.flags = 0;
svCreate.save_data_space_id = FsSaveDataSpaceId_User;
FsSaveDataMetaInfo meta;
memset(&meta, 0, sizeof(FsSaveDataMetaInfo));
meta.size = 0x40060;
meta.type = FsSaveDataMetaType_Thumbnail;
Result res = 0;
if(R_SUCCEEDED(res = fsCreateSaveDataFileSystem(&attr, &svCreate, &meta)))
{
data::loadUsersTitles(false);
ui::ttlRefresh();
}
else
{
ui::showPopMessage(POP_FRAME_DEFAULT, ui::saveCreateFailed.c_str());
fs::logWrite("SaveCreate Failed -> %X\n", res);
}
t->finished = true;
}
static void createSaveData(void *a)
{
ui::newThread(createSaveData_t, a, NULL);
data::user *u = data::getCurrentUser();
u128 uid = u->getUID128();
//Device, BCAT, and Cache are hardcoded user IDs in JKSV's data
uint64_t tid = 0;
switch(uid)
{
case 0://This is system
break;
case 2:
tid = bcatSids[bcatSaveMenu->getSelected()];
fs::createSaveData(FsSaveDataType_Bcat, tid, util::u128ToAccountUID(0));
break;
case 3:
tid = devSids[deviceSaveMenu->getSelected()];
fs::createSaveData(FsSaveDataType_Device, tid, util::u128ToAccountUID(0));
break;
case 5:
tid = cacheSids[cacheSaveMenu->getSelected()];
fs::createSaveData(FsSaveDataType_Cache, tid, util::u128ToAccountUID(0));
break;
default:
tid = accSids[saveCreateMenu->getSelected()];
fs::createSaveData(FsSaveDataType_Account, tid, u->getUID());
break;
}
}
static void usrOptCreateAllSaves(void *a)
{
data::user *u = data::getCurrentUser();
int devPos = ui::usrMenu->getOptPos("Device");
int bcatPos = ui::usrMenu->getOptPos("BCAT");
int sel = ui::usrMenu->getSelected();
if(sel < devPos)
{
AccountUid uid = u->getUID();
for(unsigned i = 0; i < accSids.size(); i++)
fs::createSaveData(FsSaveDataType_Account, accSids[i], uid);
}
else if(sel == devPos)
{
for(unsigned i = 0; i < devSids.size(); i++)
fs::createSaveData(FsSaveDataType_Device, devSids[i], util::u128ToAccountUID(0));
}
else if(sel == bcatPos)
{
for(unsigned i = 0; i < bcatSids.size(); i++)
fs::createSaveData(FsSaveDataType_Bcat, bcatSids[i], util::u128ToAccountUID(0));
}
}
//Sets up save create menus
@ -348,11 +287,6 @@ static void initSaveCreateMenus()
bcatSids.clear();
cacheSids.clear();
accCreate = {FsSaveDataType_Account, saveCreateMenu};
devCreate = {FsSaveDataType_Device, deviceSaveMenu};
bcatCreate = {FsSaveDataType_Bcat, bcatSaveMenu};
cacheCreate = {FsSaveDataType_Cache, cacheSaveMenu};
//Group into vectors to match
for(auto& t : data::titles)
{
@ -380,25 +314,25 @@ static void initSaveCreateMenus()
for(unsigned i = 0; i < accSids.size(); i++)
{
saveCreateMenu->addOpt(NULL, data::getTitleNameByTID(accSids[i]));
saveCreateMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, &accCreate);
saveCreateMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, NULL);
}
for(unsigned i = 0; i < devSids.size(); i++)
{
deviceSaveMenu->addOpt(NULL, data::getTitleNameByTID(devSids[i]));
deviceSaveMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, &devCreate);
deviceSaveMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, NULL);
}
for(unsigned i = 0; i < bcatSids.size(); i++)
{
bcatSaveMenu->addOpt(NULL, data::getTitleNameByTID(bcatSids[i]));
bcatSaveMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, &bcatCreate);
bcatSaveMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, NULL);
}
for(unsigned i = 0; i < cacheSids.size(); i++)
{
cacheSaveMenu->addOpt(NULL, data::getTitleNameByTID(cacheSids[i]));
cacheSaveMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, &cacheCreate);
cacheSaveMenu->optAddButtonEvent(i, HidNpadButton_A, createSaveData, NULL);
}
}
@ -451,10 +385,15 @@ void ui::usrInit()
usrOptPanel = new ui::slideOutPanel(410, 720, 0, ui::SLD_RIGHT, usrOptPanelDraw);
ui::registerPanel(usrOptPanel);
usrOptMenu->addOpt(NULL, ui::usrOptString[0]);
for(int i = 0; i < 3; i++)
usrOptMenu->addOpt(NULL, ui::getUIString("userOptions", i));
//Create Save Data
usrOptMenu->optAddButtonEvent(0, HidNpadButton_A, usrOptSaveCreate, usrMenu);
usrOptMenu->addOpt(NULL, ui::usrOptString[1]);
usrOptMenu->optAddButtonEvent(1, HidNpadButton_A, usrOptDeleteAllUserSaves, NULL);
//Create All
usrOptMenu->optAddButtonEvent(1, HidNpadButton_A, usrOptCreateAllSaves, NULL);
//Delete All
usrOptMenu->optAddButtonEvent(2, HidNpadButton_A, usrOptDeleteAllUserSaves, NULL);
usrOptMenu->setActive(false);
saveCreatePanel = new ui::slideOutPanel(512, 720, 0, ui::SLD_RIGHT, saveCreatePanelDraw);
@ -471,7 +410,7 @@ void ui::usrInit()
initSaveCreateMenus();
usrHelpX = 1220 - gfx::getTextWidth(ui::userHelp.c_str(), 18);
usrHelpX = 1220 - gfx::getTextWidth(ui::getUICString("helpUser", 0), 18);
}
void ui::usrExit()
@ -528,7 +467,6 @@ void ui::usrUpdate()
void ui::usrDraw(SDL_Texture *target)
{
usrMenu->draw(target, &ui::txtCont, false);
if(ui::mstate == USR_SEL)
gfx::drawTextf(NULL, 18, usrHelpX, 673, &ui::txtCont, ui::userHelp.c_str());
gfx::drawTextf(NULL, 18, usrHelpX, 673, &ui::txtCont, ui::getUICString("helpUser", 0));
}

View File

@ -188,7 +188,7 @@ static inline std::string getTimeString(const uint32_t& _h, const uint32_t& _m)
std::string util::getInfoString(data::user& u, const uint64_t& tid)
{
data::titleInfo *tinfo = data::getTitleInfoByTID(tid);
data::userTitleInfo *userTinfo = &u.titleInfo[data::selData];
data::userTitleInfo *userTinfo = data::getCurrentUserTitleInfo();
std::string ret = tinfo->title + "\n";
@ -226,8 +226,11 @@ std::string util::getInfoString(data::user& u, const uint64_t& tid)
break;
case FsSaveDataType_Cache:
ret += "Cache Storage\n";
ret += "Save Index: " + std::to_string(data::curData.saveInfo.save_data_index) + "\n";
{
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
ret += "Cache Storage\n";
ret += "Save Index: " + std::to_string(d->saveInfo.save_data_index) + "\n";
}
break;
case FsSaveDataType_SystemBcat:
@ -354,11 +357,11 @@ void util::setCPU(uint32_t hz)
void util::checkForUpdate(void *a)
{
threadInfo *t = (threadInfo *)a;
t->status->setStatus("Checking for Updates...");
t->status->setStatus(ui::getUICString("threadStatusCheckingForUpdate", 0));
std::string gitJson = getJSONURL(NULL, "https://api.github.com/repos/J-D-K/JKSV/releases/latest");
if(gitJson.empty())
{
ui::showPopMessage(POP_FRAME_DEFAULT, ui::errorConnecting.c_str());
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("onlineErrorConnecting", 0));
t->finished = true;
return;
}
@ -372,7 +375,7 @@ void util::checkForUpdate(void *a)
//This can throw false positives as is. need to fix sometime
if(year > BLD_YEAR || month > BLD_MON || month > BLD_DAY)
{
t->status->setStatus("Downloading Update...");
t->status->setStatus(ui::getUICString("threadStatusDownloadingUpdate", 0));
//dunno about NSP yet...
json_object *assets, *asset0, *dlUrl;
json_object_object_get_ex(jobj, "assets", &assets);
@ -387,7 +390,7 @@ void util::checkForUpdate(void *a)
fclose(jksvOut);
}
else
ui::showPopMessage(POP_FRAME_DEFAULT, ui::noUpdate.c_str());
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("onlineNoUpdates", 0));
json_object_put(jobj);
t->finished = true;