diff --git a/Makefile b/Makefile index 13c1867..c13fba6 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ INCLUDES := inc EXEFS_SRC := exefs_src APP_TITLE := JKSV APP_AUTHOR := JK -APP_VERSION := 06.14.2021 +APP_VERSION := 07.09.2021 ROMFS := romfs ICON := icon.jpg diff --git a/README.MD b/README.MD index f5932a1..6f06ec2 100644 --- a/README.MD +++ b/README.MD @@ -70,40 +70,17 @@ JKSV on Switch started as a small project/port to test some things and get famil * Rescan Titles reloads save data information. This can be used to reload after a process is terminated or when options are changed. * Mount Process RomFS opens the title's romfs that is taken over to launch the homebrew menu. This only works as an NRO. The NSP will only open JKSV's own RomFS. * Backup JKSV folder writes the entire JKSV folder to a ZIP archive and places it in your JKSV folder. - -6. Options - * Include Dev Sv will add Device Save games such as Animal Crossing to your user account saves for easier access. - * AutoBackup will create a backup of your current save before restoring just in case. - * Overclock will clock your Switch's CPU to 1224MHz on boot. - * Hold to [X] will disable needing to hold down A to confirm an action - * Force Mount will only allow JKSV to list titles it can open. Disabling will give a complete list of all saves on your system - * Account Sys. Saves will allow you to see and open system saves associated with user accounts - * Write to Sys. Saves will allow you to write data to system save archives. This can be dangerous. - * Text UI mode enables a simplified UI that only uses text menus - * Direct FS Commands uses a simple wrapper instead of libnx's stdio. - * Skip User Select jumps directly to the first user found instead of requiring a user to be selected. - * Export to ZIP uses minizip to compress your save data to a ZIP archive instead of a folder full of files. This saves space and makes moving saves more convienient. - * Sort changes the way titles are sorted. Alphabetically, Most time played, or by last title played. - -**IMPORTANT**: Press Plus to Exit JKSV. JKSV saves all config, favorites, and the blacklist when exited. Pressing the home button and closing that way will not allow this to take place. + +**NOTE**: Press Plus to Exit JKSV. JKSV saves all config, favorites, and the blacklist when exited. Pressing the home button and closing that way will not allow this to take place. ## Building: 1. Requires [devkitPro](https://devkitpro.org/) and [libnx](https://github.com/switchbrew/libnx) -2. Requires switch- - * freetype - * libpng - * zlib - * libjpeg-turbo - * curl - * libjson-c - * sdl2 - * sdl2_image - * libwebp - +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. * [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 * [JamePeng](https://github.com/JamePeng) For the Simplified Chinese translation. diff --git a/inc/data.h b/inc/data.h index e077bbc..081311f 100644 --- a/inc/data.h +++ b/inc/data.h @@ -1,6 +1,4 @@ -#ifndef DATA_H -#define DATA_H - +#pragma once #include #include @@ -10,14 +8,16 @@ #include "gfx.h" #define curUser users[data::selUser] -#define curData users[data::selUser].titles[data::selData] +#define curData users[data::selUser].titleInfo[data::selData] -#define BLD_MON 06 -#define BLD_DAY 14 +#define BLD_MON 7 +#define BLD_DAY 9 #define BLD_YEAR 2021 namespace data { + extern bool forceMount; + //Loads user + title info void init(); void exit(); @@ -29,61 +29,27 @@ namespace data void loadFav(); void saveFav(); void loadDefs(); - void exportIcons(); //Draws some stats to the upper left corner void dispStats(); - //Class to store title info - class titledata + //Global stuff for all titles/saves + typedef struct { - public: - titledata() = default; - //Attempts to read title's info - titledata(const FsSaveDataInfo& inf, NsApplicationControlData *dat); + NacpStruct nacp; + std::string title, safeTitle, author;//Shortcuts sorta. + SDL_Texture *icon; + bool fav; + } titleInfo; - //Returns title + title without forbidden chars - std::string getTitle() const { return title;} - std::string getTitleSafe() const { return titleSafe; } - std::string getAuthor() const { return author; } - - //Creates title folder - void createDir() const; - //Returns folder path - std::string getPath() const; - - //returns save_data_id string. only used for helping identify nand files - std::string getTIDStr() const; - std::string getSaveIDStr() const; - - uint64_t getID() const { return id; } - uint64_t getSaveID() const { return saveID; } - uint16_t getSaveIndex() const { return saveIndex; } - FsSaveDataType getType() const { return (FsSaveDataType)saveDataType; } - void setID(const uint64_t& _id){ id = _id; } - void setIndex(const uint16_t& _ind){ saveIndex = _ind; } - void setType(FsSaveDataType type) { saveDataType = type; } - void setFav(bool setFav) { favorite = setFav; } - bool getFav() const { return favorite; } - void assignIcon(); - void drawIcon(bool full, unsigned x, unsigned y); - void drawIconFav(bool full, unsigned x, unsigned y); - void setPlayTime(const uint32_t& _p){ playMins = _p; } - uint32_t getPlayTime() const { return playMins; } - void setLastTimeStamp(const uint32_t& _ts){ lastTimeStamp = _ts; } - uint32_t getLastTimeStamp() const { return lastTimeStamp; } - void setLaunchCount(const uint32_t& _lc) { launchCount = _lc; } - uint32_t getLaunchCount() const { return launchCount; } - - private: - SDL_Texture *icon; - uint8_t saveDataType; - std::string title, titleSafe, author; - uint64_t id, saveID; - uint16_t saveIndex; - uint32_t playMins, lastTimeStamp, launchCount; - bool favorite = false; - }; + //Holds stuff specific to user's titles/saves + typedef struct + { + //Makes it easier to grab id + uint64_t saveID; + FsSaveDataInfo saveInfo; + PdmPlayStatistics playStats; + } userTitleInfo; //Class to store user info + titles class user @@ -107,13 +73,11 @@ namespace data std::string getUsername() const { return username; } std::string getUsernameSafe() const { return userSafe; } - //Vector for storing save data info for user - std::vector titles; - void loadPlayTimes(); + SDL_Texture *getUserIcon(){ return userIcon; } + void delIcon(){ SDL_DestroyTexture(userIcon); } - void drawIcon(int x, int y) { gfx::texDraw(userIcon, x, y); } - void drawIconHalf(int x, int y) { gfx::texDrawStretch(userIcon, x, y, 128, 128); } - void delIcon() { SDL_DestroyTexture(userIcon); } + std::vector titleInfo; + void addUserTitleInfo(const uint64_t& _tid, const FsSaveDataInfo *_saveInfo, const PdmPlayStatistics *_stats); private: AccountUid userID; @@ -123,17 +87,34 @@ namespace data SDL_Texture *userIcon; }; - //Gets total count of save containers - unsigned getTotalSaves(); - //Adds title to blacklist - void blacklistAdd(data::titledata& t); + void blacklistAdd(const uint64_t& tid); //Adds title to favorite list - void favoriteTitle(data::titledata& t); + void favoriteTitle(const uint64_t& tid); + + bool isFavorite(const uint64_t& tid); //User vector extern std::vector users; - extern std::unordered_map icons; + //Title data/info map + extern std::unordered_map titles; + + //Gets pointer to info + data::titleInfo *getTitleInfoByTID(const uint64_t& tid); + + //More shortcut functions + std::string getTitleNameByTID(const uint64_t& tid); + std::string getTitleSafeNameByTID(const uint64_t& tid); + SDL_Texture *getTitleIconByTID(const uint64_t& tid); + inline int getTitleIndexInUser(const data::user& u, const uint64_t& sid) + { + for(unsigned i = 0; i < u.titleInfo.size(); i++) + { + if(u.titleInfo[i].saveID == sid) + return i; + } + return -1; + } //Options and info //Restores config to default @@ -143,5 +124,3 @@ namespace data extern bool incDev, autoBack, ovrClk, holdDel, holdRest, holdOver, forceMount, accSysSave, sysSaveWrite, directFsCmd, skipUser, zip, langOverride; extern uint8_t sortType; } - -#endif // DATA_H diff --git a/inc/file.h b/inc/file.h index 961963a..457cd26 100644 --- a/inc/file.h +++ b/inc/file.h @@ -1,5 +1,4 @@ -#ifndef FILE_H -#define FILE_H +#pragma once #include #include @@ -11,6 +10,7 @@ #include "fsfile.h" #include "data.h" +#include "miscui.h" namespace fs { @@ -18,7 +18,7 @@ namespace fs void exit(); //Mounts usr's save data for open. Returns false it fails - bool mountSave(const data::user& usr, const data::titledata& open); + bool mountSave(const FsSaveDataInfo& _m); inline bool unmountSave() { return fsdevUnmountDevice("sv") == 0; } void copyFile(const std::string& from, const std::string& to); @@ -127,9 +127,19 @@ namespace fs bool opened = false; }; + typedef struct + { + ui::menu *m; + fs::dirList *d; + } backupArgs; + + //Take a pointer to backupArgs^ + void createNewBackup(void *a); + void overwriteBackup(void *a); + void restoreBackup(void *a); + void deleteBackup(void *a); + void logOpen(); void logWrite(const char *fmt, ...); void logClose(); } - -#endif // FILE_H diff --git a/inc/fld.h b/inc/fld.h new file mode 100644 index 0000000..e018243 --- /dev/null +++ b/inc/fld.h @@ -0,0 +1,9 @@ +#pragma once + +namespace ui +{ + void fldInit(); + void fldExit(); + void fldUpdate(); + void fldDraw(); +} diff --git a/inc/fsfile.h b/inc/fsfile.h index 87087c0..40fb2b2 100644 --- a/inc/fsfile.h +++ b/inc/fsfile.h @@ -1,5 +1,4 @@ -#ifndef FSFILE_H -#define FSFILE_H +#pragma once #include #include @@ -97,5 +96,3 @@ inline void fsfputc(int ch, FSFILE *_f) { fsfwrite(&ch, 1, 1, _f); } #ifdef __cplusplus } #endif - -#endif diff --git a/inc/gfx.h b/inc/gfx.h index e554345..f449821 100644 --- a/inc/gfx.h +++ b/inc/gfx.h @@ -1,5 +1,4 @@ -#ifndef GFX_H -#define GFX_H +#pragma once #include @@ -9,51 +8,67 @@ namespace gfx void init(); void exit(); - void clear(const SDL_Color *c); void present(); SDL_Texture *loadJPEGMem(const void *jpegData, size_t jpegSize); SDL_Texture *loadImageFile(const char *file); - void drawTextf(int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...); - void drawTextfWrap(int fontSize, int x, int y, int maxWidth, const SDL_Color* c, const char *fmt, ...); + void drawTextf(SDL_Texture *target, int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...); + void drawTextfWrap(SDL_Texture *target, int fontSize, int x, int y, int maxWidth, const SDL_Color* c, const char *fmt, ...); size_t getTextWidth(const char *str, int fontSize); //Shortcuts for drawing - inline void texDraw(SDL_Texture *tex, int x, int y) + inline void texDraw(SDL_Texture *target, SDL_Texture *tex, int x, int y) { int tW = 0, tH = 0; if(SDL_QueryTexture(tex, NULL, NULL, &tW, &tH) == 0) { + SDL_SetRenderTarget(gfx::render, target); SDL_Rect src = {0, 0, tW, tH}; SDL_Rect pos = {x, y, tW, tH}; - SDL_RenderCopy(render, tex, &src, &pos); + SDL_RenderCopy(gfx::render, tex, &src, &pos); } } - inline void texDrawStretch(SDL_Texture *tex, int x, int y, int w, int h) + inline void texDrawStretch(SDL_Texture *target, SDL_Texture *tex, int x, int y, int w, int h) { int tW = 0, tH = 0; if(SDL_QueryTexture(tex, NULL, NULL, &tW, &tH) == 0) { + SDL_SetRenderTarget(gfx::render, target); SDL_Rect src = {0, 0, tW, tH}; SDL_Rect pos = {x, y, w, h}; - SDL_RenderCopy(render, tex, &src, &pos); + SDL_RenderCopy(gfx::render, tex, &src, &pos); } } - inline void drawLine(const SDL_Color *c, int x1, int y1, int x2, int y2) + inline void texDrawPart(SDL_Texture *target, SDL_Texture *tex, int srcX, int srcY, int srcW, int srcH, int dstX, int dstY) { - SDL_SetRenderDrawColor(render, c->r, c->g, c->b, c->a); - SDL_RenderDrawLine(render, x1, y1, x2, y2); + SDL_Rect src = {srcX, srcY, srcW, srcH}; + SDL_Rect dst = {dstX, dstY, srcW, srcH}; + SDL_SetRenderTarget(gfx::render, target); + SDL_RenderCopy(gfx::render, tex, &src, &dst); } - inline void drawRect(const SDL_Color *c, int x, int y, int w, int h) + inline void drawLine(SDL_Texture *target, const SDL_Color *c, int x1, int y1, int x2, int y2) { - SDL_SetRenderDrawColor(render, c->r, c->g, c->b, c->a); + SDL_SetRenderTarget(gfx::render, target); + SDL_SetRenderDrawColor(gfx::render, c->r, c->g, c->b, c->a); + SDL_RenderDrawLine(gfx::render, x1, y1, x2, y2); + } + + inline void drawRect(SDL_Texture *target, const SDL_Color *c, int x, int y, int w, int h) + { + SDL_SetRenderTarget(gfx::render, target); + SDL_SetRenderDrawColor(gfx::render, c->r, c->g, c->b, c->a); SDL_Rect rect = {x, y, w, h}; - SDL_RenderFillRect(render, &rect); + SDL_RenderFillRect(gfx::render, &rect); + } + + inline void clearTarget(SDL_Texture *target, const SDL_Color *clear) + { + SDL_SetRenderTarget(gfx::render, target); + SDL_SetRenderDrawColor(gfx::render, clear->r, clear->g, clear->b, clear->a); + SDL_RenderClear(gfx::render); } } - -#endif // GFX_H diff --git a/inc/menu.h b/inc/menu.h deleted file mode 100644 index ed1b6b7..0000000 --- a/inc/menu.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef MENU_H -#define MENU_H - -#include -#include - -#include "gfx.h" -#include "miscui.h" - -namespace ui -{ - class menu - { - public: - void setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW); - //Adds option - void addOpt(const std::string& add); - //Changes opt text - void editOpt(int ind, const std::string& ch); - //Clears menu stuff - ~menu(); - - //Handles controller input - void handleInput(const uint64_t& down, const uint64_t& held); - - //Returns selected option - int getSelected() { return selected; } - - //Draws the menu at x and y. rectWidth is the width of the rectangle drawn under the selected - void draw(const SDL_Color *textClr); - - //Clears and resets menu - void reset(); - - //Resets selected + start - void resetSel() { selected = 0; start = 0; } - - //Adjusts things after changes are made - void adjust(); - - private: - //drawing x and y + rectangle width - unsigned x = 0, y = 0, rW = 0, rY = 0; - //Options vector - std::vector opt; - //Selected + frame counting for auto-scroll - int selected = 0, fc = 0, start = 0; - //How much we shift the color of the rectangle - uint8_t clrSh = 0; - bool clrAdd = true; - }; -} - -#endif diff --git a/inc/miscui.h b/inc/miscui.h index b134db7..549401b 100644 --- a/inc/miscui.h +++ b/inc/miscui.h @@ -1,39 +1,139 @@ -#ifndef MISCUI_H -#define MISCUI_H +#pragma once +#include + +#include "type.h" #include "gfx.h" -#define PROG_MAX_WIDTH_DEFAULT 576 #define POP_FRAME_DEFAULT 130 +#define MENU_FONT_SIZE_DEFAULT 18 +#define MENU_MAX_SCROLL_DEFAULT 15 + +typedef enum +{ + FUNC_A, + FUNC_B, + FUNC_X, + FUNC_Y, +} funcBtn; + +typedef enum +{ + MENU_X, + MENU_Y, + MENU_RECT_WIDTH, + MENU_FONT_SIZE, + MENU_MAX_SCROLL +} menuParams; + //For smaller classes that aren't easy to get lost in and general functions namespace ui { + typedef struct + { + SDL_Texture *icn = NULL; + std::string txt; + funcPtr func[4] = {NULL}; + void *argPtr[4] = {NULL}; + } menuOpt; + + class menu + { + public: + menu() = default; + + //X, Y, Rect width/Max length, Font size, max to show + void setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW, const unsigned& _fS, const unsigned& _mL); + void editParam(int _param, unsigned newVal); + + //Gets executed when menu changes at all + void setOnChangeFunc(funcPtr func){ onChange = func; } + + //executed when .update() is called. + void setCallback(funcPtr _callback, void *args) { callback = _callback; callbackArgs = args; } + + //Adds option. + void addOpt(SDL_Texture *_icn, const std::string& add); + //Changes opt text + void editOpt(int ind, SDL_Texture *_icn, const std::string& ch); + + void setOptFunc(unsigned _ind, unsigned _funcbtn, funcPtr _func, void *args); + void updateOptArgs(unsigned _ind, unsigned _funcbtn, void *args){ opt[_ind].argPtr[_funcbtn] = args; } + + int getOptPos(const std::string& txt); + + //Clears menu stuff + ~menu(); + + //Handles controller input and executes functions for buttons if they're set + void update(); + + //Returns selected option + int getSelected() { return selected; } + + //Draws the menu at x and y. rectWidth is the width of the rectangle drawn under the selected + void draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText); + + //Clears and resets menu + void reset(); + + //Resets selected + start + void resetSel() { selected = 0; start = 0; } + + //Enables control/disables drawing select box + void setActive(bool _set); + bool getActive() { return isActive; } + + private: + //drawing x and y + rectangle width/height. Height is calc'd with font size + int x = 0, y = 0, rW = 0, rY = 0, fSize = 0, rH = 0, mL = 0; + //Options vector + std::vector opt; + //Selected + frame counting for auto-scroll + int selected = 0, fc = 0, start = 0; + //How much we shift the color of the rectangle + uint8_t clrSh = 0; + bool clrAdd = true, isActive = true; + funcPtr onChange = NULL, callback = NULL; + void *callbackArgs, *funcArgs; + }; + //Progress bar for showing loading. Mostly so people know it didn't freeze class progBar { public: - progBar() = default; - //Constructor. _max is the maximum value - progBar(const uint64_t& _max, const uint64_t& _maxWidth) { max = _max; maxWidth = _maxWidth; } - - void setMax(const uint64_t& _max, const uint64_t& _maxWidth){ max = _max; maxWidth = _maxWidth; } + progBar(const uint64_t& _max) { max = _max; } //Updates progress void update(const uint64_t& _prog); - void incProgress(unsigned inc){ prog += inc; } - //Draws with text at top void draw(const std::string& text, const std::string& head); - //Draws without dialog box - void drawNoDialog(int x, int y); + private: + uint64_t max, prog; + float width; + }; + + //_draw is called and passed the panel texture/target when this.draw() is called. + class slideOutPanel + { + public: + slideOutPanel(int _w, int _h, int _y, funcPtr _draw); + ~slideOutPanel(); + + void openPanel() { open = true; } + void closePanel() { open = false; } + bool isOpen() { return open; } + void draw(const SDL_Color *backCol); private: - uint64_t max, prog, maxWidth; - float width; + int w, h, x = 1280, y, slideSpd = 0; + bool open = false; + SDL_Texture *panel; + funcPtr drawFunc; }; //General use @@ -41,11 +141,10 @@ namespace ui bool confirm(bool hold, const char *fmt, ...); bool confirmTransfer(const std::string& f, const std::string& t); bool confirmDelete(const std::string& p); - void drawTextbox(int x, int y, int w, int h); + void drawBoundBox(SDL_Texture *target, int x, int y, int w, int h, uint8_t clrSh); + void drawTextbox(SDL_Texture *target, int x, int y, int w, int h); //Popup from freebird void showPopup(unsigned frames, const char *fmt, ...); void drawPopup(const uint64_t& down); } - -#endif // MISCUI_H diff --git a/inc/ttl.h b/inc/ttl.h new file mode 100644 index 0000000..66327ff --- /dev/null +++ b/inc/ttl.h @@ -0,0 +1,13 @@ +#pragma once + +namespace ui +{ + void ttlInit(); + void ttlExit(); + + //JIC for func ptr + void setupTiles(void *); + void ttlReset(); + void ttlUpdate(); + void ttlDraw(SDL_Texture *target); +} diff --git a/inc/txtui.h b/inc/txtui.h deleted file mode 100644 index 1454152..0000000 --- a/inc/txtui.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef TXTUI_H -#define TXTUI_H - -#include "data.h" - -namespace ui -{ - void textUserPrep(); - void textTitlePrep(data::user& u); - - void textUserMenuUpdate(const uint64_t& down, const uint64_t& held); - void drawTextUserMenu(); - - void textTitleMenuUpdate(const uint64_t& down, const uint64_t& held); - void drawTextTitleMenu(); - - void textFolderMenuUpdate(const uint64_t& down, const uint64_t& held); - void drawTextFolderMenu(); - - void updateExMenu(const uint64_t& down, const uint64_t& held); - void drawExMenu(); - - void exMenuPrep(); - - //Options - void optMenuInit(); - void updateOptMenu(const uint64_t& down, const uint64_t& held); - void drawOptMenu(); -} - -#endif diff --git a/inc/type.h b/inc/type.h new file mode 100644 index 0000000..47cbde0 --- /dev/null +++ b/inc/type.h @@ -0,0 +1,4 @@ +#pragma once + +//Misc stuff for new menu code +typedef void (*funcPtr)(void *); diff --git a/inc/ui.h b/inc/ui.h index 86ef0af..efcc7d6 100644 --- a/inc/ui.h +++ b/inc/ui.h @@ -1,19 +1,18 @@ -#ifndef UI_H -#define UI_H +#pragma once #include #include #include #include "data.h" -#include "uistr.h" #include "gfx.h" //ui headers - split up to keep a bit more organized -#include "menu.h" #include "miscui.h" -#include "txtui.h" -#include "uiupdate.h" +#include "uistr.h" +#include "usr.h" +#include "ttl.h" +#include "fld.h" enum menuState { @@ -38,10 +37,12 @@ namespace ui //pad data cause i don't know where else to put it extern PadState pad; - static inline void updatePad() { padUpdate(&pad); } + extern HidTouchScreenState touchState; + static inline void updateInput() { touchState = {0}; padUpdate(&pad); hidGetTouchScreenStates(&touchState, 1); } inline uint64_t padKeysDown() { return padGetButtonsDown(&pad); } inline uint64_t padKeysHeld() { return padGetButtons(&pad); } inline uint64_t padKeysUp() { return padGetButtonsUp(&pad); } + inline void touchGetXY(uint32_t *x, uint32_t *y) { *x = touchState.touches[0].x; *y = touchState.touches[0].y; } inline void changeState(int newState) { @@ -52,7 +53,7 @@ namespace ui //Holds theme set id extern ColorSetId thmID; - //Both UI modes need access to thi + //Both UI modes need access to this extern std::string folderMenuInfo; /*Colors @@ -60,10 +61,13 @@ namespace ui txtCont = text that contrasts clearClr txtDiag = text color for dialogs */ - extern SDL_Color clearClr, txtCont, txtDiag, rectLt, rectSh, tboxClr, sideRect; + extern SDL_Color clearClr, transparent, txtCont, txtDiag, rectLt, rectSh, tboxClr, sideRect, divClr, heartColor, slidePanelColor; //Textbox graphics extern SDL_Texture *cornerTopLeft, *cornerTopRight, *cornerBottomLeft, *cornerBottomRight; + //Menu bounding + extern SDL_Texture *mnuTopLeft, *mnuTopRight, *mnuBotLeft, *mnuBotRight; + //Covers left and right of progress bar to fake being not a rectangle. extern SDL_Texture *progCovLeft, *progCovRight, *diaBox; @@ -77,22 +81,26 @@ namespace ui void init(); void exit(); + //Adds a panel pointer to a vector since they need to be drawn over everything else + void addPanel(slideOutPanel *sop); + + //Just draws a screen and flips JIC boot takes long. void showLoadScreen(); //Clears and draws general stuff used by multiple screens void drawUI(); - //Draws selection box - void drawBoundBox(int x, int y, int w, int h, int clrSh); - //switch case so we don't have problems with multiple main loops like 3DS - void runApp(const uint64_t& down, const uint64_t& held); + bool runApp(); //These are shared by both folder menus - void createNewBackup(const uint64_t& held); - void overwriteBackup(unsigned ind); - void restoreBackup(unsigned ind); - void deleteBackup(unsigned ind); -} + //Expects a uint64_t passed for held buttons + void createNewBackup(void *a); + //all exepect an unsigned int containing menu's selected + void overwriteBackup(void *a); + void restoreBackup(void *a); + void deleteBackup(void *a); -#endif + //Used for multiple menu functions/callback + void toTTL(void *); +} diff --git a/inc/uistr.h b/inc/uistr.h index 7e77019..240aa62 100644 --- a/inc/uistr.h +++ b/inc/uistr.h @@ -1,15 +1,15 @@ -#ifndef UISTR_H -#define UISTR_H +#pragma once //Strings since translation support namespace ui { - extern const std::string loadGlyphArray[8]; + void loadTrans(); extern std::string author, userHelp, titleHelp, folderHelp, optHelp, \ confBlacklist, confOverwrite, confRestore, confDel, confCopy, \ confEraseNand, confEraseFolder, yt, nt, on, off, confirmHead, \ - copyHead, noSavesFound, errorConnecting, noUpdate; + copyHead, noSavesFound, errorConnecting, noUpdate, saveCreated, saveCreateFailed, \ + saveDataReset, saveDataResetSuccess, saveDataDeleteSuccess; //Strings for file mode menu extern std::string advMenuStr[6]; @@ -17,12 +17,12 @@ namespace ui extern std::string exMenuStr[11]; //Strings for options menu extern std::string optMenuStr[15]; - //Strings for options explanations - extern std::string optMenuExp[15]; //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[1]; + //Strings for title options + extern std::string titleOptString[4]; } - -#endif // UISTR_H diff --git a/inc/uiupdate.h b/inc/uiupdate.h deleted file mode 100644 index f73fd9e..0000000 --- a/inc/uiupdate.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef UIUPDATE_H -#define UIUPDATE_H - -//Contains declarations of ui updating functions - -namespace ui -{ - void updateUserMenu(const uint64_t& down, const uint64_t& held); - void drawUserMenu(); - - void updateTitleMenu(const uint64_t& down, const uint64_t& held); - void drawTitleMenu(); - - void updateFolderMenu(const uint64_t& down, const uint64_t& held); - void drawFolderMenu(); - - void updateAdvMode(const uint64_t& down, const uint64_t& held); - void drawAdvMode(); - - //needed here since it uses static menu - void folderMenuPrepare(data::user& usr, data::titledata& dat); - void advCopyMenuPrep(); - void advModePrep(const std::string& svDev, const FsSaveDataType& _type, bool commitOnWrite); -} - -#endif diff --git a/inc/usr.h b/inc/usr.h new file mode 100644 index 0000000..2ee8276 --- /dev/null +++ b/inc/usr.h @@ -0,0 +1,10 @@ +#pragma once + +namespace ui +{ + void usrInit(); + void usrExit(); + void usrMenuSetActive(bool _set); + void usrUpdate(); + void usrDraw(SDL_Texture *target); +} diff --git a/inc/util.h b/inc/util.h index 55a072c..54213c8 100644 --- a/inc/util.h +++ b/inc/util.h @@ -28,11 +28,11 @@ namespace util std::string safeString(const std::string& s); - std::string getInfoString(const data::user& u, const data::titledata& d); + std::string getInfoString(data::user& u, const uint64_t& tid); std::string getStringInput(const std::string& def, const std::string& head, size_t maxLength, unsigned dictCnt, const std::string dictWords[]); - std::string generateAbbrev(const data::titledata& dat); + std::string generateAbbrev(const uint64_t& tid); //removes char from C++ string void stripChar(char _c, std::string& _s); @@ -56,6 +56,33 @@ namespace util return ret; } + inline std::string getIDStr(const uint64_t& _id) + { + char tmp[18]; + sprintf(tmp, "%016lX", _id); + return std::string(tmp); + } + + inline std::string getIDStrLower(const uint64_t& _id) + { + char tmp[18]; + sprintf(tmp, "%08X", (uint32_t)_id); + return std::string(tmp); + } + + inline std::string generatePathByTID(const uint64_t& tid) + { + return fs::getWorkDir() + data::getTitleSafeNameByTID(tid) + "/"; + } + + inline void createTitleDirectoryByTID(const uint64_t& tid) + { + std::string makePath = fs::getWorkDir() + data::getTitleSafeNameByTID(tid); + mkdir(makePath.c_str(), 777); + } + + Result accountDeleteUser(AccountUid *uid); + void setCPU(uint32_t hz); void checkForUpdate(); } diff --git a/src/data.cpp b/src/data.cpp index 26351d0..84c4fb5 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -11,14 +11,8 @@ #include "file.h" #include "util.h" -//Color for favorite hearts -const SDL_Color heartColor = {0xFF, 0x44, 0x44, 0xFF}; - //FsSaveDataSpaceId_All doesn't work for SD -static const unsigned saveOrder [] = -{ - 0, 1, 2, 3, 4, 100, 101 -}; +static const unsigned saveOrder [] = { 0, 1, 2, 3, 4, 100, 101 }; int data::selUser = 0, data::selData = 0; @@ -30,8 +24,8 @@ SetLanguage data::sysLang; //Options bool data::incDev = false, data::autoBack = true, data::ovrClk = false, data::holdDel = true, data::holdRest = true, data::holdOver = true; -bool data::forceMount = true, data::accSysSave = false, data::sysSaveWrite = false, data::directFsCmd = false, data::skipUser = false, data::zip = false; -bool data::langOverride = false; +bool data::forceMount = true, data::accSysSave = false, data::sysSaveWrite = false, data::directFsCmd = false, data::skipUser = false, data::zip = false, data::langOverride = false; + uint8_t data::sortType = 0; //For other save types @@ -40,25 +34,29 @@ static bool sysBCATPushed = false, cachePushed = false, tempPushed = false; static std::vector blacklist; static std::vector favorites; static std::unordered_map pathDefs; -std::unordered_map data::icons; +std::unordered_map data::titles; + +static SDL_Texture *iconMask; //Sorts titles by sortType static struct { - bool operator()(const data::titledata& a, const data::titledata& b) + bool operator()(const data::userTitleInfo& a, const data::userTitleInfo& b) { //Favorites override EVERYTHING - if(a.getFav() != b.getFav()) return a.getFav(); + if(data::isFavorite(a.saveID) != data::isFavorite(b.saveID)) return data::isFavorite(a.saveID); switch(data::sortType) { case 0://Alpha { + std::string titleA = data::getTitleNameByTID(a.saveID); + std::string titleB = data::getTitleNameByTID(b.saveID); uint32_t tmpA, tmpB; - for(unsigned i = 0; i < a.getTitle().length(); ) + for(unsigned i = 0; i < titleA.length(); ) { - ssize_t uCnt = decode_utf8(&tmpA, (const uint8_t *)&a.getTitle().data()[i]); - decode_utf8(&tmpB, (const uint8_t *)&b.getTitle().data()[i]); + ssize_t uCnt = decode_utf8(&tmpA, (const uint8_t *)&titleA.data()[i]); + decode_utf8(&tmpB, (const uint8_t *)&titleB.data()[i]); tmpA = tolower(tmpA), tmpB = tolower(tmpB); if(tmpA != tmpB) return tmpA < tmpB; @@ -69,11 +67,11 @@ static struct break; case 1://Most played - return a.getPlayTime() > b.getPlayTime(); + return a.playStats.playtimeMinutes > b.playStats.playtimeMinutes; break; case 2://Last Played - return a.getLastTimeStamp() > b.getLastTimeStamp(); + return a.playStats.last_timestampUser > b.playStats.last_timestampUser; break; } return false; @@ -98,7 +96,7 @@ static bool blacklisted(const uint64_t& tid) return false; } -static bool isFavorite(const uint64_t& tid) +bool data::isFavorite(const uint64_t& tid) { for(uint64_t& fid : favorites) if(tid == fid) return true; @@ -114,31 +112,6 @@ static bool isDefined(const uint64_t& id) return false; } -static SDL_Texture *createDeviceIcon() -{ - return util::createIconGeneric("\ue121", 192); -} - -static inline void loadCreateIcon(const uint64_t& _id, size_t _sz, const NsApplicationControlData *_d) -{ - data::icons[_id] = gfx::loadJPEGMem(_d->icon, _sz); -} - -static void loadCreateSystemIcon(const uint64_t& _id) -{ - char tmp[16]; - sprintf(tmp, "%08X", (uint32_t)_id); - - data::icons[_id] = util::createIconGeneric(tmp, 32); -} - -static inline std::string getIDStr(const uint64_t& _id) -{ - char tmp[18]; - sprintf(tmp, "%016lX", _id); - return std::string(tmp); -} - static inline bool accountSystemSaveCheck(const FsSaveDataInfo& _inf) { if(_inf.save_data_type == FsSaveDataType_System && util::accountUIDToU128(_inf.uid) != 0 && !data::accSysSave) @@ -150,30 +123,92 @@ static inline bool accountSystemSaveCheck(const FsSaveDataInfo& _inf) //Minimal init/test to avoid loading and creating things I don't need static bool testMount(const FsSaveDataInfo& _inf) { + bool ret = false; if(!data::forceMount) return true; - bool ret = false; - uint64_t id; - data::user tmpusr; - data::titledata tmpdat; - - if(_inf.save_data_type == FsSaveDataType_System || _inf.save_data_type == FsSaveDataType_SystemBcat) - id = _inf.system_save_data_id; - else - id = _inf.application_id; - - tmpusr.setUID(_inf.uid); - tmpdat.setID(id); - tmpdat.setIndex(_inf.save_data_index); - tmpdat.setType((FsSaveDataType)_inf.save_data_type); - - if((ret = fs::mountSave(tmpusr, tmpdat))) + if((ret = fs::mountSave(_inf))) fs::unmountSave(); return ret; } +static inline void addTitleToList(const uint64_t& tid) +{ + uint64_t outSize = 0; + NsApplicationControlData *ctrlData = new NsApplicationControlData; + NacpLanguageEntry *ent; + Result ctrlRes = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, ctrlData, sizeof(NsApplicationControlData), &outSize); + Result nacpRes = nacpGetLanguageEntry(&ctrlData->nacp, &ent); + size_t iconSize = outSize - sizeof(ctrlData->nacp); + + if(R_SUCCEEDED(ctrlRes) && !(outSize < sizeof(ctrlData->nacp)) && R_SUCCEEDED(nacpRes) && iconSize > 0) + { + //Copy nacp + memcpy(&data::titles[tid].nacp, &ctrlData->nacp, sizeof(NacpStruct)); + + //Setup 'shortcuts' to strings + NacpLanguageEntry *ent; + nacpGetLanguageEntry(&data::titles[tid].nacp, &ent); + data::titles[tid].title = ent->name; + data::titles[tid].author = ent->author; + if(isDefined(tid)) + data::titles[tid].safeTitle = pathDefs[tid]; + else if((data::titles[tid].safeTitle = util::safeString(ent->name)) == "") + data::titles[tid].safeTitle = util::getIDStr(tid); + + if(data::isFavorite(tid)) + data::titles[tid].fav = true; + + data::titles[tid].icon = gfx::loadJPEGMem(ctrlData->icon, iconSize); + } + else + { + memset(&data::titles[tid].nacp, 0, sizeof(NacpStruct)); + data::titles[tid].title = util::getIDStr(tid); + data::titles[tid].author = "Someone?"; + if(isDefined(tid)) + data::titles[tid].safeTitle = pathDefs[tid]; + else + data::titles[tid].safeTitle = util::getIDStr(tid); + + data::titles[tid].icon = util::createIconGeneric(util::getIDStrLower(tid).c_str(), 32); + } + + delete ctrlData; +} + +static inline bool titleIsLoaded(const uint64_t& tid) +{ + auto findTid = data::titles.find(tid); + + return findTid == data::titles.end() ? false : true; +} + +static void loadUserAccounts() +{ + s32 total = 0; + AccountUid *uids = new AccountUid[8]; + if(R_SUCCEEDED(accountListAllUsers(uids, 8, &total))) + { + for(int i = 0; i < total; i++) + data::users.emplace_back(uids[i], ""); + } + delete[] uids; +} + +//This can load titles installed without having save data +static void loadTitlesFromRecords() +{ + NsApplicationRecord nsRecord; + int32_t entryCount = 0, recordOffset = 0; + while(R_SUCCEEDED(nsListApplicationRecord(&nsRecord, 1, recordOffset++, &entryCount)) && entryCount > 0) + { + if(!titleIsLoaded(nsRecord.application_id)) + addTitleToList(nsRecord.application_id); + } +} + bool data::loadUsersTitles(bool clearUsers) { static unsigned systemUserCount = 3; @@ -181,25 +216,28 @@ bool data::loadUsersTitles(bool clearUsers) FsSaveDataInfo info; s64 total = 0; + loadTitlesFromRecords(); + //Clear titles for(data::user& u : data::users) - u.titles.clear(); + u.titleInfo.clear(); if(clearUsers) { - systemUserCount = 3; + systemUserCount = 4; for(data::user& u : data::users) u.delIcon(); - data::users.clear(); + + loadUserAccounts(); sysBCATPushed = false; cachePushed = false; tempPushed = false; - users.emplace_back(util::u128ToAccountUID(3), "Device Saves", createDeviceIcon()); + users.emplace_back(util::u128ToAccountUID(3), "Device"); users.emplace_back(util::u128ToAccountUID(2), "BCAT"); + users.emplace_back(util::u128ToAccountUID(5), "Cache"); users.emplace_back(util::u128ToAccountUID(0), "System"); } - NsApplicationControlData *dat = new NsApplicationControlData; for(unsigned i = 0; i < 7; i++) { if(R_FAILED(fsOpenSaveDataInfoReader(&it, (FsSaveDataSpaceId)saveOrder[i]))) @@ -207,8 +245,14 @@ bool data::loadUsersTitles(bool clearUsers) while(R_SUCCEEDED(fsSaveDataInfoReaderRead(&it, &info, 1, &total)) && total != 0) { + uint64_t saveID = 0; + if(info.save_data_type == FsSaveDataType_System || info.save_data_type == FsSaveDataType_SystemBcat) + saveID = info.system_save_data_id; + else + saveID = info.application_id; + //Don't bother with this stuff - if(blacklisted(info.application_id) || blacklisted(info.save_data_id) || !accountSystemSaveCheck(info) || !testMount(info)) + if(blacklisted(saveID) || !accountSystemSaveCheck(info) || !testMount(info)) continue; switch(info.save_data_type) @@ -252,35 +296,41 @@ bool data::loadUsersTitles(bool clearUsers) break; } + if(!titleIsLoaded(saveID)) + addTitleToList(saveID); + int u = getUserIndex(info.uid); if(u == -1) { users.emplace(data::users.end() - systemUserCount, info.uid, ""); u = getUserIndex(info.uid); } - users[u].titles.emplace_back(info, dat); + + PdmPlayStatistics playStats; + if(info.save_data_type == FsSaveDataType_Account || info.save_data_type == FsSaveDataType_Device) + pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(info.application_id, info.uid, false, &playStats); + else + memset(&playStats, 0, sizeof(PdmPlayStatistics)); + + users[u].addUserTitleInfo(saveID, &info, &playStats); } fsSaveDataInfoReaderClose(&it); } - delete dat; - if(data::incDev) + /*if(data::incDev) { //Get reference to device save user - data::user& dev = data::users[data::users.size() - 3]; - for(unsigned i = 0; i < users.size() - 3; i++) + data::user& dev = data::users[data::users.size() - 4]; + for(unsigned i = 0; i < users.size() - 4; i++) { //Not needed but makes this easier to read data::user& u = data::users[i]; u.titles.insert(u.titles.end(), dev.titles.begin(), dev.titles.end()); } - } + }*/ for(data::user& u : data::users) - { - u.loadPlayTimes(); - std::sort(u.titles.begin(), u.titles.end(), sortTitles); - } + std::sort(u.titleInfo.begin(), u.titleInfo.end(), sortTitles); return true; } @@ -305,11 +355,10 @@ void data::init() void data::exit() { for(data::user& u : data::users) u.delIcon(); - for(auto& icn : icons) - { - if(icn.second) - SDL_DestroyTexture(icn.second); - } + for(auto& tinfo : titles) + SDL_DestroyTexture(tinfo.second.icon); + + SDL_DestroyTexture(iconMask); saveFav(); saveCfg(); @@ -317,95 +366,24 @@ void data::exit() util::setCPU(1020000000); } -data::titledata::titledata(const FsSaveDataInfo& inf, NsApplicationControlData *dat) +data::titleInfo *data::getTitleInfoByTID(const uint64_t& tid) { - size_t outSz = 0; - NacpLanguageEntry *ent = NULL; - memset(dat, 0, sizeof(NsApplicationControlData)); - - if(inf.save_data_type == FsSaveDataType_System || inf.save_data_type == FsSaveDataType_SystemBcat) - id = inf.system_save_data_id; - else - id = inf.application_id; - - saveID = inf.save_data_id; - saveIndex = inf.save_data_index; - saveDataType = inf.save_data_type; - - Result ctrlDataRes = nsGetApplicationControlData(NsApplicationControlSource_Storage, id, dat, sizeof(NsApplicationControlData), &outSz); - Result nacpRes = nacpGetLanguageEntry(&dat->nacp, &ent); - size_t icnSize = outSz - sizeof(dat->nacp); - auto icnInd = icons.find(id); - if(R_SUCCEEDED(ctrlDataRes) && !(outSz < sizeof(dat->nacp)) && R_SUCCEEDED(nacpRes) && ent != NULL && icnSize > 0) - { - title.assign(ent->name); - author.assign(ent->author); - if(isDefined(id)) - titleSafe = util::safeString(pathDefs[id]); - else if((titleSafe = util::safeString(title)) == "") - titleSafe = getIDStr(id); - - if(icnInd == icons.end()) - loadCreateIcon(id, icnSize, dat); - - assignIcon(); - } - else - { - if(icnInd == icons.end()) - loadCreateSystemIcon(id); - title = getIDStr(id); - titleSafe = getIDStr(id); - assignIcon(); - } - favorite = isFavorite(id); + return &titles[tid]; } -void data::titledata::createDir() const +std::string data::getTitleNameByTID(const uint64_t& tid) { - mkdir(std::string(fs::getWorkDir() + titleSafe).c_str(), 777); + return titles[tid].title; } -std::string data::titledata::getPath() const +std::string data::getTitleSafeNameByTID(const uint64_t& tid) { - return std::string(fs::getWorkDir() + titleSafe + "/"); + return titles[tid].safeTitle; } -std::string data::titledata::getTIDStr() const +SDL_Texture *data::getTitleIconByTID(const uint64_t& tid) { - return getIDStr(id); -} - -std::string data::titledata::getSaveIDStr() const -{ - return getIDStr(saveID); -} - -void data::titledata::assignIcon() -{ - icon = icons[id]; -} - -void data::titledata::drawIcon(bool full, unsigned x, unsigned y) -{ - if(full) - gfx::texDraw(icon, x, y); - else - gfx::texDrawStretch(icon, x, y, 128, 128); -} - -void data::titledata::drawIconFav(bool full, unsigned x, unsigned y) -{ - if(full) - { - gfx::texDraw(icon, x, y); - gfx::drawTextf(48, x + 16, y + 16, &heartColor, "♥"); - } - else - { - gfx::texDrawStretch(icon, x, y, 128, 128); - gfx::drawTextf(24, x + 8, y + 8, &heartColor, "♥"); - } + return titles[tid].icon; } data::user::user(const AccountUid& _id, const std::string& _backupName) @@ -438,17 +416,18 @@ data::user::user(const AccountUid& _id, const std::string& _backupName) } else { - username = _backupName.empty() ? getIDStr((uint64_t)uID128) : _backupName; - userSafe = _backupName.empty() ? getIDStr((uint64_t)uID128) : _backupName; - userIcon = util::createIconGeneric(_backupName.c_str(), 32); + username = _backupName.empty() ? util::getIDStr((uint64_t)uID128) : _backupName; + userSafe = _backupName.empty() ? util::getIDStr((uint64_t)uID128) : _backupName; + userIcon = util::createIconGeneric(_backupName.c_str(), 40); } - titles.reserve(32); + titles.reserve(64); } data::user::user(const AccountUid& _id, const std::string& _backupName, SDL_Texture *img) : user(_id, _backupName) { delIcon(); userIcon = img; + titles.reserve(64); } void data::user::setUID(const AccountUid& _id) @@ -457,52 +436,13 @@ void data::user::setUID(const AccountUid& _id) uID128 = util::accountUIDToU128(_id); } -void data::user::loadPlayTimes() +void data::user::addUserTitleInfo(const uint64_t& tid, const FsSaveDataInfo *_saveInfo, const PdmPlayStatistics *_stats) { - PdmPlayStatistics stats; - for(data::titledata& _d : titles) - { - switch(_d.getType()) - { - case FsSaveDataType_Account: - pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(_d.getID(), userID, false, &stats); - _d.setPlayTime(stats.playtimeMinutes); - _d.setLastTimeStamp(stats.last_timestampUser); - _d.setLaunchCount(stats.totalLaunches); - break; - - case FsSaveDataType_Device: - pdmqryQueryPlayStatisticsByApplicationId(_d.getID(), false, &stats); - _d.setPlayTime(stats.playtimeMinutes); - _d.setLastTimeStamp(stats.last_timestampNetwork); - _d.setLaunchCount(stats.totalLaunches); - break; - - default: - _d.setPlayTime(0); - _d.setLastTimeStamp(0); - _d.setLaunchCount(0); - break; - } - } -} - -unsigned data::getTotalSaves() -{ - unsigned ret = 0; - FsSaveDataInfoReader read; - FsSaveDataInfo tmp; - int64_t out = 0; - for(unsigned i = 0; i < 7; i++) - { - if(R_FAILED(fsOpenSaveDataInfoReader(&read, (FsSaveDataSpaceId)saveOrder[i]))) - continue; - - while(R_SUCCEEDED(fsSaveDataInfoReaderRead(&read, &tmp, 1, &out)) && out != 0) - ++ret; - } - fsSaveDataInfoReaderClose(&read); - return ret; + data::userTitleInfo newInfo; + newInfo.saveID = tid; + memcpy(&newInfo.saveInfo, _saveInfo, sizeof(FsSaveDataInfo)); + memcpy(&newInfo.playStats, _stats, sizeof(PdmPlayStatistics)); + titleInfo.emplace_back(newInfo); } void data::loadBlacklist() @@ -519,49 +459,38 @@ void data::saveBlackList() { std::string blPath = fs::getWorkDir() + "blacklist.txt"; FILE *bl = fopen(blPath.c_str(), "w"); - for(uint64_t& id : blacklist) - fprintf(bl, "0x%016lX\n", id); + for(uint64_t id : blacklist) + fprintf(bl, "#%s\n0x%016lX\n", data::getTitleNameByTID(id).c_str(), id); fclose(bl); } -void data::blacklistAdd(titledata& t) +void data::blacklistAdd(const uint64_t& tid) { - uint64_t tid = t.getID(); for(data::user& _u : data::users) { - for(unsigned i = 0; i < _u.titles.size(); i++) - if(_u.titles[i].getID() == tid) _u.titles.erase(_u.titles.begin() + i); + for(unsigned i = 0; i < _u.titleInfo.size(); i++) + if(_u.titleInfo[i].saveID == tid) _u.titleInfo.erase(_u.titleInfo.begin() + i); } blacklist.push_back(tid); } -void data::favoriteTitle(titledata& t) +void data::favoriteTitle(const uint64_t& tid) { - uint64_t tid = t.getID(); - if(!t.getFav()) + if(!isFavorite(tid)) { - for(data::user& _u : data::users) - { - for(unsigned i = 0; i < _u.titles.size(); i++) - if(_u.titles[i].getID() == tid) _u.titles[i].setFav(true); - - std::sort(_u.titles.begin(), _u.titles.end(), sortTitles); - } + titles[tid].fav = true; favorites.push_back(tid); } else { + titles[tid].fav = false; auto ind = std::find(favorites.begin(), favorites.end(), tid); favorites.erase(ind); - for(data::user& _u : data::users) - { - for(unsigned i = 0; i < _u.titles.size(); i++) - if(_u.titles[i].getID() == tid) _u.titles[i].setFav(false); - - std::sort(_u.titles.begin(), _u.titles.end(), sortTitles); - } } + + for(auto &u : data::users) + std::sort(u.titleInfo.begin(), u.titleInfo.end(), sortTitles); } void data::loadCfg() @@ -585,7 +514,6 @@ void data::loadCfg() data::forceMount = cfgIn >> 57 & 1; data::accSysSave = cfgIn >> 56 & 1; data::sysSaveWrite = cfgIn >> 55 & 1; - ui::textMode = cfgIn >> 54 & 1; data::directFsCmd = cfgIn >> 53 & 1; data::skipUser = cfgIn >> 52 & 1; data::zip = cfgIn >> 51 & 1; @@ -609,7 +537,6 @@ void data::saveCfg() cfgOut |= (uint64_t)data::forceMount << 57; cfgOut |= (uint64_t)data::accSysSave << 56; cfgOut |= (uint64_t)data::sysSaveWrite << 55; - cfgOut |= (uint64_t)ui::textMode << 54; cfgOut |= (uint64_t)data::directFsCmd << 53; cfgOut |= (uint64_t)data::skipUser << 52; cfgOut |= (uint64_t)data::zip << 51; @@ -636,7 +563,6 @@ void data::restoreDefaultConfig() data::skipUser = false; data::zip = false; data::sortType = 0; - data::langOverride = false; } void data::loadFav() @@ -680,11 +606,10 @@ void data::dispStats() //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.titles.size()) + "\n"; + stats += u.getUsername() + ": " + std::to_string(u.titleInfo.size()) + "\n"; stats += "Current User: " + data::curUser.getUsername() + "\n"; - stats += "Current Title: " + data::curData.getTitle() + "\n"; - stats += "Safe Title: " + data::curData.getTitleSafe() + "\n"; - stats += "Icon count: " + std::to_string(icons.size()) + "\n"; + stats += "Current Title: " + data::getTitleNameByTID(data::curData.saveID) + "\n"; + stats += "Safe Title: " + data::getTitleSafeNameByTID(data::curData.saveID) + "\n"; stats += "Sort Type: " + std::to_string(data::sortType) + "\n"; - gfx::drawTextf(16, 8, 8, &green, stats.c_str()); + gfx::drawTextf(NULL, 16, 2, 2, &green, stats.c_str()); } diff --git a/src/file.cpp b/src/file.cpp index 7d36ebe..8f0f4a4 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -131,25 +131,25 @@ void fs::exit() fs::logClose(); } -bool fs::mountSave(const data::user& usr, const data::titledata& open) +bool fs::mountSave(const FsSaveDataInfo& _m) { Result svOpen; - switch(open.getType()) + switch(_m.save_data_type) { case FsSaveDataType_System: - svOpen = fsOpen_SystemSaveData(&sv, FsSaveDataSpaceId_System, open.getID(), usr.getUID()); + svOpen = fsOpen_SystemSaveData(&sv, FsSaveDataSpaceId_System, _m.save_data_id, _m.uid); break; case FsSaveDataType_Account: - svOpen = fsOpen_SaveData(&sv, open.getID(), usr.getUID()); + svOpen = fsOpen_SaveData(&sv, _m.application_id, _m.uid); break; case FsSaveDataType_Bcat: - svOpen = fsOpen_BcatSaveData(&sv, open.getID()); + svOpen = fsOpen_BcatSaveData(&sv, _m.application_id); break; case FsSaveDataType_Device: - svOpen = fsOpen_DeviceSaveData(&sv, open.getID()); + svOpen = fsOpen_DeviceSaveData(&sv, _m.application_id); break; case FsSaveDataType_Temporary: @@ -157,11 +157,11 @@ bool fs::mountSave(const data::user& usr, const data::titledata& open) break; case FsSaveDataType_Cache: - svOpen = fsOpen_CacheStorage(&sv, open.getID(), open.getSaveIndex()); + svOpen = fsOpen_CacheStorage(&sv, _m.application_id, _m.save_data_rank); break; case FsSaveDataType_SystemBcat: - svOpen = fsOpen_SystemBcatSaveData(&sv, open.getID()); + svOpen = fsOpen_SystemBcatSaveData(&sv, _m.application_id); break; default: @@ -371,7 +371,7 @@ void fs::copyFile(const std::string& from, const std::string& to) copyArgs *send = copyArgsCreate(from, to, "", NULL, &progress); //Setup progress bar. This thread updates screen, other handles copying - ui::progBar prog(fsize(from), PROG_MAX_WIDTH_DEFAULT); + ui::progBar prog(fsize(from)); Thread cpyThread; threadCreate(&cpyThread, copyfile_t, send, NULL, 0x4000, 0x2B, 1); @@ -448,7 +448,7 @@ void copyFileCommit_t(void *a) void fs::copyFileCommit(const std::string& from, const std::string& to, const std::string& dev) { uint64_t offset = 0; - ui::progBar prog(fsize(from), PROG_MAX_WIDTH_DEFAULT); + ui::progBar prog(fsize(from)); copyArgs *send = copyArgsCreate(from, to, dev, NULL, &offset); Thread cpyThread; @@ -501,7 +501,7 @@ void copyFileToZip_t(void *a) { if(zipWriteInFileInZip(*args->z, inBuff, readIn) != 0) { - fs::logWrite("zipWriteInFileInZip failed -> \"%s\"\n", args->from.c_str()); + fs::logWrite("Failed", "zipWriteInFileInZip -> \"%s\"\n", args->from.c_str()); break; } @@ -515,7 +515,7 @@ void copyFileToZip_t(void *a) void copyFileToZip(const std::string& from, zipFile *z) { - ui::progBar prog(fs::fsize(from), PROG_MAX_WIDTH_DEFAULT); + ui::progBar prog(fs::fsize(from)); uint64_t progress = 0; copyArgs *send = copyArgsCreate(from, "", "", z, &progress); @@ -571,7 +571,7 @@ void fs::copyZipToDir(unzFile *unz, const std::string& to, const std::string& de { std::string path = to + filename; mkdirRec(path.substr(0, path.find_last_of('/') + 1)); - ui::progBar prog(info.uncompressed_size, PROG_MAX_WIDTH_DEFAULT); + ui::progBar prog(info.uncompressed_size); size_t done = 0; //Create new empty file using FS @@ -584,6 +584,7 @@ void fs::copyZipToDir(unzFile *unz, const std::string& to, const std::string& de done += readIn; fwriteCommit(path, buff, readIn, dev); prog.update(done); + prog.draw(filename, ui::copyHead); gfx::present(); } @@ -595,6 +596,7 @@ void fs::copyZipToDir(unzFile *unz, const std::string& to, const std::string& de done += readIn; fwriteCommit(path, buff, readIn, dev); prog.update(done); + prog.draw(filename, ui::copyHead); gfx::present(); } @@ -697,23 +699,22 @@ void fs::freePathFilters() bool fs::dumpAllUserSaves(const data::user& u) { - for(unsigned i = 0; i < u.titles.size(); i++) + for(unsigned i = 0; i < u.titleInfo.size(); i++) { - ui::updatePad(); + ui::updateInput(); if(ui::padKeysDown() & HidNpadButton_B) return false; - if(fs::mountSave(u, u.titles[i])) + if(fs::mountSave(u.titleInfo[i].saveInfo)) { - u.titles[i].createDir(); - std::string filtersPath = u.titles[i].getPath() + "pathFilters.txt"; - fs::loadPathFilters(filtersPath); + util::createTitleDirectoryByTID(u.titleInfo[i].saveID); + std::string basePath = util::generatePathByTID(u.titleInfo[i].saveID); switch(data::zip) { case true: { - std::string outPath = u.titles[i].getPath() + u.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip"; + std::string outPath = basePath + u.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip"; zipFile zip = zipOpen(outPath.c_str(), 0); fs::copyDirToZip("sv:/", &zip); zipClose(zip, NULL); @@ -722,16 +723,18 @@ bool fs::dumpAllUserSaves(const data::user& u) case false: { - std::string outPath = u.titles[i].getPath() + u.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/"; + std::string outPath = basePath + u.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/"; mkdir(outPath.substr(0, outPath.length() - 1).c_str(), 777); fs::copyDirToDir("sv:/", outPath); } break; } fsdevUnmountDevice("sv"); - fs::freePathFilters(); } } + + ui::updateInput(); + return true;//? } @@ -825,6 +828,176 @@ bool fs::isDir(const std::string& _path) return stat(_path.c_str(), &s) == 0 && S_ISDIR(s.st_mode); } +void fs::createNewBackup(void *a) +{ + uint64_t held = ui::padKeysHeld(); + + std::string out; + + if(held & HidNpadButton_R) + out = data::users[data::selUser].getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD); + else if(held & HidNpadButton_L) + out = data::users[data::selUser].getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YDM); + else if(held & HidNpadButton_ZL) + out = data::users[data::selUser].getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_HOYSTE); + else + { + const std::string dict[] = + { + util::getDateTime(util::DATE_FMT_YMD), + util::getDateTime(util::DATE_FMT_YDM), + 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) + }; + out = util::getStringInput("", "Enter a name", 64, 8, dict); + } + + if(!out.empty()) + { + std::string path = util::generatePathByTID(data::curData.saveID) + out; + switch(data::zip) + { + case true: + { + path += ".zip"; + zipFile zip = zipOpen(path.c_str(), 0); + fs::copyDirToZip("sv:/", &zip); + zipClose(zip, NULL); + } + break; + + case false: + { + mkdir(path.c_str(), 777); + path += "/"; + fs::copyDirToDir("sv:/", path); + } + break; + } + ui::fldInit(); + } +} + +void fs::overwriteBackup(void *a) +{ + fs::backupArgs *in = (fs::backupArgs *)a; + ui::menu *m = in->m; + fs::dirList *d = in->d; + + unsigned ind = m->getSelected() - 1;;//Skip new + + std::string itemName = d->getItem(ind); + if(ui::confirm(data::holdOver, ui::confOverwrite.c_str(), itemName.c_str())) + { + if(d->isDir(ind)) + { + std::string toPath = util::generatePathByTID(data::curData.saveID) + itemName + "/"; + //Delete and recreate + fs::delDir(toPath); + mkdir(toPath.c_str(), 777); + fs::copyDirToDir("sv:/", toPath); + } + else if(!d->isDir(ind) && d->getItemExt(ind) == "zip") + { + std::string toPath = util::generatePathByTID(data::curData.saveID) + itemName; + fs::delfile(toPath); + zipFile zip = zipOpen(toPath.c_str(), 0); + fs::copyDirToZip("sv:/", &zip); + zipClose(zip, NULL); + } + } +} + +void fs::restoreBackup(void *a) +{ + fs::backupArgs *in = (fs::backupArgs *)a; + ui::menu *m = in->m; + fs::dirList *d = in->d; + + unsigned ind = m->getSelected() - 1; + + std::string itemName = d->getItem(ind); + if((data::curData.saveInfo.save_data_type != FsSaveDataType_System || data::sysSaveWrite) && m->getSelected() > 0 && ui::confirm(data::holdRest, ui::confRestore.c_str(), itemName.c_str())) + { + if(data::autoBack) + { + switch(data::zip) + { + case true: + { + std::string autoZip = util::generatePathByTID(data::curData.saveID) + "/AUTO " + data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip"; + zipFile zip = zipOpen(autoZip.c_str(), 0); + fs::copyDirToZip("sv:/", &zip); + zipClose(zip, NULL); + } + break; + + case false: + { + std::string autoFolder = util::generatePathByTID(data::curData.saveID) + "/AUTO - " + data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/"; + mkdir(autoFolder.substr(0, autoFolder.length() - 1).c_str(), 777); + fs::copyDirToDir("sv:/", autoFolder); + } + break; + } + } + + if(d->isDir(ind)) + { + fs::wipeSave(); + std::string fromPath = util::generatePathByTID(data::curData.saveID) + itemName + "/"; + fs::copyDirToDirCommit(fromPath, "sv:/", "sv"); + } + else if(!d->isDir(ind) && d->getItemExt(ind) == "zip") + { + fs::wipeSave(); + std::string path = util::generatePathByTID(data::curData.saveID) + itemName; + unzFile unz = unzOpen(path.c_str()); + fs::copyZipToDir(&unz, "sv:/", "sv"); + unzClose(unz); + } + else + { + //Just copy file over + std::string fromPath = util::generatePathByTID(data::curData.saveID) + itemName; + std::string toPath = "sv:/" + itemName; + fs::copyFileCommit(fromPath, toPath, "sv"); + } + } + + if(data::autoBack) + ui::fldInit(); +} + +void fs::deleteBackup(void *a) +{ + fs::backupArgs *in = (fs::backupArgs *)a; + ui::menu *m = in->m; + fs::dirList *d = in->d; + + unsigned ind = m->getSelected() - 1; + + std::string itemName = d->getItem(ind); + if(ui::confirmDelete(itemName)) + { + if(d->isDir(ind)) + { + std::string delPath = util::generatePathByTID(data::curData.saveID) + itemName + "/"; + fs::delDir(delPath); + } + else + { + std::string delPath = util::generatePathByTID(data::curData.saveID) + itemName; + fs::delfile(delPath); + } + ui::fldInit(); + } +} + void fs::logOpen() { std::string logPath = wd + "log.txt"; diff --git a/src/gfx.cpp b/src/gfx.cpp index ebf2af9..35f2851 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -9,6 +9,7 @@ #define VA_SIZE 1024 #include "gfx.h" +#include "file.h" static SDL_Window *wind; SDL_Renderer *gfx::render; @@ -29,6 +30,8 @@ static const uint32_t greenMask = 0x00FF0000; static const uint32_t blueMask = 0x0000FF00; static const uint32_t alphaMask = 0x000000FF; +static uint8_t *alphaMod; + static inline bool compClr(const SDL_Color *c1, const SDL_Color *c2) { return (c1->r == c2->r) && (c1->b == c2->b) && (c1->g == c2->g) && (c1->a == c2->a); @@ -97,6 +100,15 @@ void gfx::init() wind = SDL_CreateWindow("JKSV", 0, 0, 1280, 720, SDL_WINDOW_SHOWN); render = SDL_CreateRenderer(wind, -1, SDL_RENDERER_ACCELERATED); + + SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND); + + //Load the alpha mod to round icon corners + alphaMod = (uint8_t *)malloc(256 * 256); + FILE *modLoad = fopen("romfs:/img/icn/icon.msk", "rb"); + fread(alphaMod, 1, 256 * 256, modLoad); + fclose(modLoad); + loadSystemFont(); } @@ -106,16 +118,12 @@ void gfx::exit() SDL_Quit(); freeSystemFont(); + free(alphaMod); + for(auto c : glyphCache) SDL_DestroyTexture(c.second.tex); } -void gfx::clear(const SDL_Color *c) -{ - SDL_SetRenderDrawColor(render, c->r, c->g, c->b, c->a); - SDL_RenderClear(render); -} - void gfx::present() { SDL_RenderPresent(render); @@ -131,6 +139,9 @@ SDL_Texture *gfx::loadJPEGMem(const void *jpegData, size_t jpegsize) SDL_FreeSurface(tmpSurf); SDL_RWclose(jpeg); + + SDL_SetTextureBlendMode(ret, SDL_BLENDMODE_BLEND); + return ret; } @@ -142,6 +153,9 @@ SDL_Texture *gfx::loadImageFile(const char *file) ret = SDL_CreateTextureFromSurface(render, tmpSurf); SDL_FreeSurface(tmpSurf); + + SDL_SetTextureBlendMode(ret, SDL_BLENDMODE_BLEND); + return ret; } @@ -245,8 +259,9 @@ static inline bool specialChar(const uint32_t *p, const int *fontSize, const SDL return ret; } -void gfx::drawTextf(int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...) +void gfx::drawTextf(SDL_Texture *target, int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...) { + SDL_SetRenderTarget(gfx::render, target); char tmp[VA_SIZE]; va_list args; va_start(args, fmt); @@ -283,10 +298,12 @@ void gfx::drawTextf(int fontSize, int x, int y, const SDL_Color *c, const char * tmpX += g->advX; } } + SDL_SetRenderTarget(gfx::render, NULL); } -void gfx::drawTextfWrap(int fontSize, int x, int y, int maxWidth, const SDL_Color *c, const char *fmt, ...) +void gfx::drawTextfWrap(SDL_Texture *target, int fontSize, int x, int y, int maxWidth, const SDL_Color *c, const char *fmt, ...) { + SDL_SetRenderTarget(gfx::render, target); char tmp[VA_SIZE], wordBuff[128]; va_list args; va_start(args, fmt); @@ -307,7 +324,7 @@ void gfx::drawTextfWrap(int fontSize, int x, int y, int maxWidth, const SDL_Colo size_t width = gfx::getTextWidth(wordBuff, fontSize); - if(tmpX + width >= x + maxWidth) + if((int)(tmpX + width) >= (int)(x + maxWidth)) { tmpX = x; y += fontSize + 8; @@ -339,6 +356,7 @@ void gfx::drawTextfWrap(int fontSize, int x, int y, int maxWidth, const SDL_Colo } i += wordLength; } + SDL_SetRenderTarget(gfx::render, NULL); } size_t gfx::getTextWidth(const char *str, int fontSize) diff --git a/src/main.cpp b/src/main.cpp index fdb6874..2d47e10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,13 +1,9 @@ -#include -#include -#include -#include #include #include "gfx.h" +#include "file.h" #include "data.h" #include "ui.h" -#include "file.h" #include "util.h" extern "C" @@ -19,7 +15,7 @@ extern "C" nsInitialize(); setsysInitialize(); setInitialize(); - accountInitialize(AccountServiceType_System); + accountInitialize(AccountServiceType_Administrator); pmshellInitialize(); socketInitializeDefault(); pdmqryInitialize(); @@ -39,8 +35,6 @@ extern "C" } } -bool debDataStats = false; - int main(int argc, const char *argv[]) { romfsInit(); @@ -52,23 +46,7 @@ int main(int argc, const char *argv[]) ui::init(); romfsExit(); - while(appletMainLoop()) - { - ui::updatePad(); - - uint64_t down = ui::padKeysDown(), held = ui::padKeysHeld(); - - if(held & HidNpadButton_StickL && held & HidNpadButton_StickR) - debDataStats = true; - else if(down & HidNpadButton_Plus) - break; - - ui::runApp(down, held); - - if(debDataStats) - data::dispStats(); - gfx::present(); - } + while(ui::runApp()){ } ui::exit(); data::exit(); diff --git a/src/ui.cpp b/src/ui.cpp index fe7ea60..4f0c1fd 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -2,22 +2,21 @@ #include #include #include +#include #include #include +#include "file.h" #include "ui.h" #include "gfx.h" #include "util.h" -#include "file.h" - -//text mode -bool ui::textMode = false; //Current menu state int ui::mstate = USR_SEL, ui::prevState = USR_SEL; //pad data? PadState ui::pad; +HidTouchScreenState ui::touchState; //Theme id ColorSetId ui::thmID; @@ -26,7 +25,8 @@ ColorSetId ui::thmID; std::string ui::folderMenuInfo; //UI colors -SDL_Color ui::clearClr, ui::txtCont, ui::txtDiag, ui::rectLt, ui::rectSh, ui::tboxClr, divClr; +SDL_Color ui::clearClr, ui::txtCont, ui::txtDiag, ui::rectLt, ui::rectSh, ui::tboxClr, ui::divClr, ui::slidePanelColor; +SDL_Color ui::transparent = {0x00, 0x00, 0x00, 0x00}; //textbox pieces //I was going to flip them when I draw them, but then laziness kicked in. @@ -36,194 +36,23 @@ SDL_Texture *ui::cornerTopLeft, *ui::cornerTopRight, *ui::cornerBottomLeft, *ui: SDL_Texture *ui::progCovLeft, *ui::progCovRight, *ui::diaBox; //Menu box pieces -SDL_Texture *mnuTopLeft, *mnuTopRight, *mnuBotLeft, *mnuBotRight; +SDL_Texture *ui::mnuTopLeft, *ui::mnuTopRight, *ui::mnuBotLeft, *ui::mnuBotRight; //Select box + top left icon SDL_Texture *ui::sideBar; -static SDL_Texture *icn; +static SDL_Texture *icn, *leftPanel, *rightPanel; +static SDL_Color rectTop = {0x36, 0x36, 0x36, 0xFF}; +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; -//Map to associate external string names to unsigned ints for switch case. -static std::unordered_map 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}, - {"confirmEraseFolder", 15}, {"confirmHead", 16}, {"copyHead", 17}, {"noSavesFound", 18}, - {"advMenu", 19}, {"extMenu", 20}, {"optMenu", 21}, {"optMenuExp", 22}, {"holdingText", 23}, - {"errorConnecting", 24}, {"noUpdate", 25}, {"sortType", 26} -}; +//For shrinking left panel +unsigned leftWidth = 410; -static void loadTrans() -{ - bool transFile = fs::fileExists(fs::getWorkDir() + "trans.txt"); - if(!transFile && (data::sysLang == SetLanguage_ENUS || data::langOverride)) - return;//Don't bother loading from file. It serves as a translation guide - - std::string file; - if(transFile) - file = fs::getWorkDir() + "trans.txt"; - else - { - file = "romfs:/lang/"; - switch(data::sysLang) - { - 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; - } - } - - fs::dataFile lang(file); - while(lang.readNextLine(true)) - { - switch(uistrdef[lang.getName()]) - { - 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::confEraseFolder = 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: - { - int ind = lang.getNextValueInt(); - ui::optMenuExp[ind] = lang.getNextValueStr(); - } - 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: - ui::showMessage("*Translation File Error:*", "On Line: %s\n*%s* is not a known or valid string name.", lang.getLine(), lang.getName()); - break; - } - } -} +//Vector of pointers to slideOutPanels. Is looped and drawn last so they are always on top +std::vector panels; void ui::initTheme() { @@ -239,6 +68,7 @@ void ui::initTheme() rectSh = {0xCA, 0xCA, 0xCA, 0xFF}; tboxClr = {0x50, 0x50, 0x50, 0xFF}; divClr = {0x00, 0x00, 0x00, 0xFF}; + slidePanelColor = {0xEE, 0xEE, 0xEE, 0xDD}; break; default: @@ -253,6 +83,7 @@ void ui::initTheme() rectSh = {0x20, 0x20, 0x20, 0xFF}; tboxClr = {0xEB, 0xEB, 0xEB, 0xFF}; divClr = {0xFF, 0xFF, 0xFF, 0xFF}; + slidePanelColor = {0x2F, 0x2F, 0x2F, 0xDD}; break; } } @@ -263,6 +94,12 @@ void ui::init() mnuTopRight = gfx::loadImageFile("romfs:/img/fb/menuTopRight.png"); mnuBotLeft = gfx::loadImageFile("romfs:/img/fb/menuBotLeft.png"); mnuBotRight = gfx::loadImageFile("romfs:/img/fb/menuBotRight.png"); + + leftPanel = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET | SDL_TEXTUREACCESS_STATIC, 200, 559); + rightPanel = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET | SDL_TEXTUREACCESS_STATIC, 1080, 559); + SDL_SetTextureBlendMode(leftPanel, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(rightPanel, SDL_BLENDMODE_BLEND); + switch(ui::thmID) { case ColorSetId_Light: @@ -290,17 +127,6 @@ void ui::init() break; } - if(ui::textMode && data::skipUser) - { - ui::textTitlePrep(data::curUser); - mstate = TXT_TTL; - } - else if(ui::textMode) - mstate = TXT_USR; - else if(data::skipUser) - mstate = TTL_SEL; - - textUserPrep(); loadTrans(); //Replace the button [x] in strings that need it. Needs to be outside loadTrans so even defaults will get replaced @@ -310,9 +136,6 @@ void ui::init() util::replaceButtonsInString(ui::optHelp); util::replaceButtonsInString(ui::yt); util::replaceButtonsInString(ui::nt); - util::replaceButtonsInString(ui::optMenuExp[3]); - util::replaceButtonsInString(ui::optMenuExp[4]); - util::replaceButtonsInString(ui::optMenuExp[5]); //Calculate x position of help text userHelpX = 1220 - gfx::getTextWidth(ui::userHelp.c_str(), 18); @@ -324,13 +147,20 @@ void ui::init() padConfigureInput(1, HidNpadStyleSet_NpadStandard); padInitializeDefault(&ui::pad); - advCopyMenuPrep(); - ui::exMenuPrep(); - ui::optMenuInit(); + //Setup touch + hidInitializeTouchScreen(); + + //advCopyMenuPrep(); + ui::usrInit(); + ui::ttlInit(); } void ui::exit() { + ui::usrExit(); + ui::ttlExit(); + ui::fldExit(); + SDL_DestroyTexture(cornerTopLeft); SDL_DestroyTexture(cornerTopRight); SDL_DestroyTexture(cornerBottomLeft); @@ -343,158 +173,117 @@ void ui::exit() SDL_DestroyTexture(mnuBotLeft); SDL_DestroyTexture(mnuBotRight); + SDL_DestroyTexture(leftPanel); + SDL_DestroyTexture(rightPanel); + SDL_DestroyTexture(icn); } +void ui::addPanel(slideOutPanel *sop) +{ + panels.push_back(sop); +} + void ui::showLoadScreen() { SDL_Texture *icon = gfx::loadImageFile("romfs:/icon.png"); - gfx::clear(&ui::clearClr); - gfx::texDraw(icon, 512, 226); - gfx::drawTextf(18, 1100, 673, &ui::txtCont, "Loading..."); + gfx::clearTarget(NULL, &ui::clearClr); + gfx::texDraw(NULL, icon, 512, 232); + gfx::drawTextf(NULL, 16, 1100, 673, &ui::txtCont, "Loading..."); gfx::present(); SDL_DestroyTexture(icon); } void ui::drawUI() { - gfx::clear(&ui::clearClr); - gfx::texDraw(icn, 66, 27); - gfx::drawTextf(24, 130, 38, &ui::txtCont, "JKSV"); - gfx::drawLine(&divClr, 30, 88, 1250, 88); - gfx::drawLine(&divClr, 30, 648, 1250, 648); + gfx::clearTarget(NULL, &ui::clearClr); + gfx::clearTarget(leftPanel, &transparent); + gfx::clearTarget(rightPanel, &transparent); + + gfx::drawLine(NULL, &divClr, 30, 88, 1250, 88); + gfx::drawLine(NULL, &divClr, 30, 648, 1250, 648); + gfx::texDraw(NULL, icn, 66, 27); + gfx::drawTextf(NULL, 24, 130, 38, &ui::txtCont, "JKSV"); //Version / translation author - gfx::drawTextf(12, 8, 700, &ui::txtCont, "v. %02d.%02d.%04d", BLD_MON, BLD_DAY, BLD_YEAR); + gfx::drawTextf(NULL, 12, 8, 700, &ui::txtCont, "v. %02d.%02d.%04d", BLD_MON, BLD_DAY, BLD_YEAR); if(author != "NULL") - gfx::drawTextf(12, 8, 682, &ui::txtCont, "Translation: %s", author.c_str()); + gfx::drawTextf(NULL, 12, 8, 682, &ui::txtCont, "Translation: %s", author.c_str()); - switch(mstate) + gfx::texDraw(leftPanel, sideBar, 0, 89); + ui::usrDraw(leftPanel); + ui::ttlDraw(rightPanel); + gfx::texDraw(NULL, rightPanel, 200, 89); + gfx::texDraw(NULL, leftPanel, 0, 89); + ui::fldDraw(); + for(slideOutPanel *s : panels) + s->draw(&ui::slidePanelColor); +} + +static bool debugDisp = false; + +bool ui::runApp() +{ + ui::updateInput(); + uint64_t down = ui::padKeysDown(); + + if(down & HidNpadButton_StickL && down & HidNpadButton_StickR) + debugDisp = true; + else if(down & HidNpadButton_Plus) + return false; + + switch(ui::mstate) { case USR_SEL: - gfx::drawTextf(18, userHelpX, 673, &ui::txtCont, userHelp.c_str()); - ui::drawUserMenu(); + usrUpdate(); break; case TTL_SEL: - gfx::drawTextf(18, titleHelpX, 673, &ui::txtCont, titleHelp.c_str()); - ui::drawTitleMenu(); + ttlUpdate(); break; case FLD_SEL: - gfx::texDraw(sideBar, 0, 89); - gfx::drawTextf(18, folderHelpX, 673, &ui::txtCont, folderHelp.c_str()); - ui::drawFolderMenu(); - break; - - case TXT_USR: - gfx::texDraw(sideBar, 0, 89); - gfx::drawTextf(18, userHelpX, 673, &ui::txtCont, userHelp.c_str()); - ui::drawTextUserMenu(); - break; - - case TXT_TTL: - gfx::texDraw(sideBar, 0, 89); - gfx::drawTextf(18, titleHelpX, 673, &ui::txtCont, titleHelp.c_str()); - ui::drawTextTitleMenu(); - break; - - case TXT_FLD: - gfx::texDraw(sideBar, 0, 89); - gfx::drawTextf(18, folderHelpX, 673, &ui::txtCont, folderHelp.c_str()); - ui::drawTextFolderMenu(); - break; - - case EX_MNU: - gfx::texDraw(sideBar, 0, 89); - ui::drawExMenu(); + fldUpdate(); break; case OPT_MNU: - gfx::texDraw(sideBar, 0, 89); - ui::drawOptMenu(); - break; - - case ADV_MDE: - gfx::drawRect(&ui::txtCont, 640, 88, 1, 559); - drawAdvMode(); - break; - } -} - -void ui::drawBoundBox(int x, int y, int w, int h, int clrSh) -{ - SDL_Color rectClr; - - if(ui::thmID == ColorSetId_Light) - rectClr = {0xFD, 0xFD, 0xFD, 0xFF}; - else - rectClr = {0x21, 0x22, 0x21, 0xFF}; - - gfx::drawRect(&rectClr, x + 4, y + 4, w - 8, h - 8); - - rectClr = {0x00,(uint8_t)(0x88 + clrSh), (uint8_t)(0xC5 + (clrSh / 2)), 0xFF}; - - SDL_SetTextureColorMod(mnuTopLeft, rectClr.r, rectClr.g, rectClr.b); - SDL_SetTextureColorMod(mnuTopRight, rectClr.r, rectClr.g, rectClr.b); - SDL_SetTextureColorMod(mnuBotLeft, rectClr.r, rectClr.g, rectClr.b); - SDL_SetTextureColorMod(mnuBotRight, rectClr.r, rectClr.g, rectClr.b); - - //top - gfx::texDraw(mnuTopLeft, x, y); - gfx::drawRect(&rectClr, x + 4, y, w - 8, 4); - gfx::texDraw(mnuTopRight, (x + w) - 4, y); - - //mid - gfx::drawRect(&rectClr, x, y + 4, 4, h - 8); - gfx::drawRect(&rectClr, (x + w) - 4, y + 4, 4, h - 8); - - //bottom - gfx::texDraw(mnuBotLeft, x, (y + h) - 4); - gfx::drawRect(&rectClr, x + 4, (y + h) - 4, w - 8, 4); - gfx::texDraw(mnuBotRight, (x + w) - 4, (y + h) - 4); -} - -void ui::runApp(const uint64_t& down, const uint64_t& held) -{ - switch(mstate) - { - case USR_SEL: - updateUserMenu(down, held); - break; - - case TTL_SEL: - updateTitleMenu(down, held); - break; - - case FLD_SEL: - updateFolderMenu(down, held); - break; - - case ADV_MDE: - updateAdvMode(down, held); - break; - - case TXT_USR: - textUserMenuUpdate(down, held); - break; - - case TXT_TTL: - textTitleMenuUpdate(down, held); - break; - - case TXT_FLD: - textFolderMenuUpdate(down, held); + /*optMenu.update(); + if(down & HidNpadButton_B) + { + ui::changeState(USR_SEL); + mainMenu.setActive(true); + optMenu.setActive(false); + }*/ break; case EX_MNU: - updateExMenu(down, held); - break; - - case OPT_MNU: - updateOptMenu(down, held); + /*extMenu.update(); + if(down & HidNpadButton_B) + { + ui::changeState(USR_SEL); + mainMenu.setActive(true); + extMenu.setActive(false); + }*/ break; } + drawUI(); - drawPopup(down); + drawPopup(ui::padKeysDown()); + if(debugDisp) + data::dispStats(); + + gfx::present(); + + return true; +} + +void ui::toTTL(void *a) +{ + if(data::curUser.titleInfo.size() > 0) + { + ui::changeState(TTL_SEL); + ui::usrMenuSetActive(false); + } + else + ui::showPopup(POP_FRAME_DEFAULT, ui::noSavesFound.c_str(), data::curUser.getUsername().c_str()); } diff --git a/src/ui/advmode.cpp b/src/ui/advmode.cpp index 6f64e51..590e1fb 100644 --- a/src/ui/advmode.cpp +++ b/src/ui/advmode.cpp @@ -2,11 +2,10 @@ #include #include +#include "file.h" #include "ui.h" #include "miscui.h" -#include "uiupdate.h" #include "util.h" -#include "file.h" //Text menus static ui::menu saveMenu, sdMenu, copyMenu; @@ -342,20 +341,20 @@ void performCopyMenuOps() } -void ui::advCopyMenuPrep() +void advCopyMenuPrep() { for(unsigned i = 0; i < 6; i++) - copyMenu.addOpt(ui::advMenuStr[i]); + copyMenu.addOpt(NULL, ui::advMenuStr[i]); } -void ui::advModePrep(const std::string& svDev, const FsSaveDataType& _type, bool commitOnWrite) +void advModePrep(const std::string& svDev, const FsSaveDataType& _type, bool commitOnWrite) { commit = commitOnWrite; type = _type; - saveMenu.setParams(30, 98, 602); - sdMenu.setParams(648, 98, 602); - copyMenu.setParams(472, 278, 304); + saveMenu.setParams(30, 98, 602, MENU_FONT_SIZE_DEFAULT, MENU_MAX_SCROLL_DEFAULT); + sdMenu.setParams(648, 98, 602, MENU_FONT_SIZE_DEFAULT, MENU_MAX_SCROLL_DEFAULT); + copyMenu.setParams(472, 278, 304, MENU_FONT_SIZE_DEFAULT, MENU_MAX_SCROLL_DEFAULT); savePath = svDev, dev = svDev; sdPath = "sdmc:/"; @@ -369,13 +368,13 @@ void ui::advModePrep(const std::string& svDev, const FsSaveDataType& _type, bool advMenuCtrl = 0; } -void ui::drawAdvMode() +void drawAdvMode() { - saveMenu.draw(&ui::txtCont); - sdMenu.draw(&ui::txtCont); + saveMenu.draw(NULL, &ui::txtCont, true); + sdMenu.draw(NULL, &ui::txtCont, true); - gfx::drawTextfWrap(14, 30, 654, 600, &ui::txtCont, savePath.c_str()); - gfx::drawTextfWrap(14, 640, 654, 600, &ui::txtCont, sdPath.c_str()); + gfx::drawTextfWrap(NULL, 14, 30, 654, 600, &ui::txtCont, savePath.c_str()); + gfx::drawTextfWrap(NULL, 14, 640, 654, 600, &ui::txtCont, sdPath.c_str()); //draw copy menu if it's supposed to be up if(advMenuCtrl == 2) @@ -383,38 +382,38 @@ void ui::drawAdvMode() switch(advPrev) { case 0: - copyMenu.setParams(176, 278, 304); - copyMenu.editOpt(0, advMenuStr[0] + "sdmc"); - ui::drawTextbox(168, 236, 320, 268); - gfx::drawTextf(18, 176, 250, &ui::txtDiag, dev.c_str()); + copyMenu.setParams(176, 278, 304, MENU_FONT_SIZE_DEFAULT, MENU_MAX_SCROLL_DEFAULT); + copyMenu.editOpt(0, NULL, ui::advMenuStr[0] + "sdmc"); + ui::drawTextbox(NULL, 168, 236, 320, 268); + gfx::drawTextf(NULL, 18, 176, 250, &ui::txtDiag, dev.c_str()); break; case 1: - copyMenu.setParams(816, 278, 304); - copyMenu.editOpt(0, advMenuStr[0] + dev); - ui::drawTextbox(808, 236, 320, 268); - gfx::drawTextf(18, 816, 250, &ui::txtDiag, "SDMC"); + copyMenu.setParams(816, 278, 304, MENU_FONT_SIZE_DEFAULT, MENU_MAX_SCROLL_DEFAULT); + copyMenu.editOpt(0, NULL, ui::advMenuStr[0] + dev); + ui::drawTextbox(NULL, 808, 236, 320, 268); + gfx::drawTextf(NULL, 18, 816, 250, &ui::txtDiag, "SDMC"); break; } - copyMenu.draw(&ui::txtDiag); + copyMenu.draw(NULL, &ui::txtDiag, true); } } -void ui::updateAdvMode(const uint64_t& down, const uint64_t& held) +void updateAdvMode(const uint64_t& down, const uint64_t& held) { //0 = save; 1 = sd; 2 = cpy switch(advMenuCtrl) { case 0: - saveMenu.handleInput(down, held); + saveMenu.update(); break; case 1: - sdMenu.handleInput(down, held); + sdMenu.update(); break; case 2: - copyMenu.handleInput(down, held); + copyMenu.update(); break; } @@ -511,18 +510,18 @@ void ui::updateAdvMode(const uint64_t& down, const uint64_t& held) } else if(down & HidNpadButton_Minus) { - switch(prevState) + switch(ui::prevState) { case EX_MNU: - mstate = EX_MNU; + ui::mstate = EX_MNU; break; case TTL_SEL: - mstate = TTL_SEL; + ui::mstate = TTL_SEL; break; default: - mstate = ui::textMode ? TXT_FLD : FLD_SEL; + ui::mstate = ui::textMode ? TXT_FLD : FLD_SEL; break; } } diff --git a/src/ui/fld.cpp b/src/ui/fld.cpp new file mode 100644 index 0000000..f05402e --- /dev/null +++ b/src/ui/fld.cpp @@ -0,0 +1,82 @@ +#include "fld.h" +#include "ui.h" +#include "file.h" +#include "data.h" +#include "util.h" + +static ui::slideOutPanel *fldSlide = NULL; +static ui::menu fldMenu; +static fs::dirList fldList; +static fs::backupArgs backargs; + +static void fldCallback(void *a) +{ + if(ui::padKeysDown() & HidNpadButton_B) + { + fs::unmountSave(); + fldSlide->closePanel(); + ui::changeState(TTL_SEL); + } +} + +static void slideDrawFunc(void *a) +{ + //Slide panel passes texture/target to draw func + SDL_Texture *panel = (SDL_Texture *)a; + fldMenu.draw(panel, &ui::txtCont, true); +} + +void ui::fldInit() +{ + //Only allocate new if null + if(!fldSlide) + { + fldSlide = new ui::slideOutPanel(410, 720, 0, slideDrawFunc); + ui::addPanel(fldSlide); + } + + fldMenu.reset(); + fldMenu.setParams(12, 32, 390, MENU_FONT_SIZE_DEFAULT, 8); + fldMenu.setCallback(fldCallback, NULL); + + util::createTitleDirectoryByTID(data::curUser.titleInfo[data::selData].saveID); + std::string folderPath = util::generatePathByTID(data::curUser.titleInfo[data::selData].saveID); + + fldList.reassign(folderPath); + fs::loadPathFilters(folderPath + "pathFilters.txt"); + + backargs = {&fldMenu, &fldList}; + + fldMenu.addOpt(NULL, "New"); + fldMenu.setOptFunc(0, FUNC_A, fs::createNewBackup, &backargs); + + //Same as above, args updated at press + for(unsigned i = 0; i < fldList.getCount(); i++) + { + fldMenu.addOpt(NULL, fldList.getItem(i)); + + //Pass the menu to the functions so selected can be grabbed + //offset i by 1 since new is always first option + fldMenu.setOptFunc(i + 1, FUNC_A, fs::overwriteBackup, &backargs); + fldMenu.setOptFunc(i + 1, FUNC_X, fs::deleteBackup, &backargs); + fldMenu.setOptFunc(i + 1, FUNC_Y, fs::restoreBackup, &backargs); + } + fldSlide->openPanel(); +} + +void ui::fldExit() +{ + if(fldSlide) + delete fldSlide; +} + +void ui::fldUpdate() +{ + fldMenu.update(); +} + +void ui::fldDraw() +{ + /*if(fldSlide) + fldSlide->draw(&slidePanelColor);*/ +} diff --git a/src/ui/fldrsel.cpp b/src/ui/fldrsel.cpp deleted file mode 100644 index 7f3a43b..0000000 --- a/src/ui/fldrsel.cpp +++ /dev/null @@ -1,227 +0,0 @@ -#include -#include -#include - -#include "ui.h" -#include "uiupdate.h" -#include "util.h" - -ui::menu folderMenu; -static fs::dirList fldList; - -void ui::folderMenuPrepare(data::user& usr, data::titledata& dat) -{ - folderMenu.setParams(466, 98, 730); - folderMenu.reset(); - - dat.createDir(); - - fldList.reassign(dat.getPath()); - fs::loadPathFilters(dat.getPath() + "pathFilters.txt"); - folderMenu.addOpt("New"); - for(unsigned i = 0; i < fldList.getCount(); i++) - folderMenu.addOpt(fldList.getItem(i)); - - folderMenu.adjust(); -} - -void ui::createNewBackup(const uint64_t& held) -{ - std::string out; - - if(held & HidNpadButton_R) - out = data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD); - else if(held & HidNpadButton_L) - out = data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YDM); - else if(held & HidNpadButton_ZL) - out = data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_HOYSTE); - else - { - const std::string dict[] = - { - util::getDateTime(util::DATE_FMT_YMD), - util::getDateTime(util::DATE_FMT_YDM), - util::getDateTime(util::DATE_FMT_HOYSTE), - util::getDateTime(util::DATE_FMT_JHK), - util::getDateTime(util::DATE_FMT_ASC), - data::curUser.getUsernameSafe(), - data::curData.getTitleSafe(), - util::generateAbbrev(data::curData) - }; - out = util::getStringInput("", "Enter a name", 64, 8, dict); - } - - if(!out.empty()) - { - std::string path = data::curData.getPath() + "/" + out; - switch(data::zip) - { - case true: - { - path += ".zip"; - zipFile zip = zipOpen(path.c_str(), 0); - fs::copyDirToZip("sv:/", &zip); - zipClose(zip, NULL); - } - break; - - case false: - { - mkdir(path.c_str(), 777); - path += "/"; - fs::copyDirToDir("sv:/", path); - } - break; - } - folderMenuPrepare(data::curUser, data::curData); - } -} - -void ui::overwriteBackup(unsigned ind) -{ - std::string itemName = fldList.getItem(ind); - if(confirm(data::holdOver, ui::confOverwrite.c_str(), itemName.c_str())) - { - if(fldList.isDir(ind)) - { - std::string toPath = data::curData.getPath() + itemName + "/"; - //Delete and recreate - fs::delDir(toPath); - mkdir(toPath.c_str(), 777); - fs::copyDirToDir("sv:/", toPath); - } - else if(!fldList.isDir(ind) && fldList.getItemExt(ind) == "zip") - { - std::string toPath = data::curData.getPath() + itemName; - fs::delfile(toPath); - zipFile zip = zipOpen(toPath.c_str(), 0); - fs::copyDirToZip("sv:/", &zip); - zipClose(zip, NULL); - } - } -} - -void ui::restoreBackup(unsigned ind) -{ - std::string itemName = fldList.getItem(ind); - if((data::curData.getType() != FsSaveDataType_System || data::sysSaveWrite) && folderMenu.getSelected() > 0 && confirm(data::holdRest, ui::confRestore.c_str(), itemName.c_str())) - { - if(data::autoBack) - { - switch(data::zip) - { - case true: - { - std::string autoZip = data::curData.getPath() + "/AUTO " + data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip"; - zipFile zip = zipOpen(autoZip.c_str(), 0); - fs::copyDirToZip("sv:/", &zip); - zipClose(zip, NULL); - } - break; - - case false: - { - std::string autoFolder = data::curData.getPath() + "/AUTO - " + data::curUser.getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/"; - mkdir(autoFolder.substr(0, autoFolder.length() - 1).c_str(), 777); - fs::copyDirToDir("sv:/", autoFolder); - } - break; - } - } - - if(fldList.isDir(ind)) - { - fs::wipeSave(); - std::string fromPath = data::curData.getPath() + itemName + "/"; - fs::copyDirToDirCommit(fromPath, "sv:/", "sv"); - } - else if(!fldList.isDir(ind) && fldList.getItemExt(ind) == "zip") - { - fs::wipeSave(); - std::string path = data::curData.getPath() + itemName; - unzFile unz = unzOpen(path.c_str()); - fs::copyZipToDir(&unz, "sv:/", "sv"); - unzClose(unz); - } - else - { - //Just copy file over - std::string fromPath = data::curData.getPath() + itemName; - std::string toPath = "sv:/" + itemName; - fs::copyFileCommit(fromPath, toPath, "sv"); - } - } - if(data::autoBack) - folderMenuPrepare(data::curUser, data::curData); -} - -void ui::deleteBackup(unsigned ind) -{ - std::string itemName = fldList.getItem(folderMenu.getSelected() - 1); - if(ui::confirmDelete(itemName)) - { - if(fldList.isDir(ind)) - { - std::string delPath = data::curData.getPath() + itemName + "/"; - fs::delDir(delPath); - } - else - { - std::string delPath = data::curData.getPath() + itemName; - fs::delfile(delPath); - } - } - folderMenuPrepare(data::curUser, data::curData); -} - -void ui::drawFolderMenu() -{ - data::curData.drawIcon(true, 96, 98); - gfx::drawTextfWrap(16, 60, 370, 360, &ui::txtCont, folderMenuInfo.c_str()); - folderMenu.draw(&ui::txtCont); -} - -void ui::updateFolderMenu(const uint64_t& down, const uint64_t& held) -{ - folderMenu.handleInput(down, held); - - switch(down) - { - case HidNpadButton_A: - if(folderMenu.getSelected() == 0) - ui::createNewBackup(held); - else - ui::overwriteBackup(folderMenu.getSelected() - 1); - break; - - case HidNpadButton_B: - fs::unmountSave(); - fs::freePathFilters(); - ui::changeState(TTL_SEL); - break; - - case HidNpadButton_X: - if(folderMenu.getSelected() > 0) - ui::deleteBackup(folderMenu.getSelected() - 1); - break; - - case HidNpadButton_Y: - if(folderMenu.getSelected() > 0) - ui::restoreBackup(folderMenu.getSelected() - 1); - break; - - case HidNpadButton_ZR: - if(data::curData.getType() != FsSaveDataType_System && confirm(true, ui::confEraseFolder.c_str(), data::curData.getTitle().c_str())) - { - fs::delDir("sv:/"); - fsdevCommitDevice("sv"); - } - break; - - case HidNpadButton_Minus: - advModePrep("sv:/", data::curData.getType(), true); - ui::changeState(ADV_MDE); - break; - } -} - diff --git a/src/ui/menu.cpp b/src/ui/menu.cpp deleted file mode 100644 index b20fe8f..0000000 --- a/src/ui/menu.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include -#include - -#include "gfx.h" -#include "menu.h" -#include "ui.h" -#include "miscui.h" - -static const SDL_Color menuColorLight = {0x32, 0x50, 0xF0, 0xFF}; -static const SDL_Color menuColorDark = {0x00, 0xFF, 0xC5, 0xFF}; - -#define HOLD_FC 10 - -void ui::menu::setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW) -{ - x = _x; - y = _y; - rW = _rW; - rY = _y; -} - -void ui::menu::addOpt(const std::string& add) -{ - if(gfx::getTextWidth(add.c_str(), 18) < rW - 32 || rW == 0) - opt.push_back(add); - else - { - std::string tmp; - for(unsigned i = 0; i < add.length(); ) - { - uint32_t tmpChr = 0; - ssize_t untCnt = decode_utf8(&tmpChr, (uint8_t *)&add.c_str()[i]); - - tmp += add.substr(i, untCnt); - i += untCnt; - if(gfx::getTextWidth(tmp.c_str(), 18) >= rW - 32) - { - opt.push_back(tmp); - break; - } - } - } -} - -void ui::menu::editOpt(int ind, const std::string& ch) -{ - opt[ind] = ch; -} - -ui::menu::~menu() -{ - opt.clear(); -} - -void ui::menu::handleInput(const uint64_t& down, const uint64_t& held) -{ - if( (held & HidNpadButton_Up) || (held & HidNpadButton_Down)) - fc++; - else - fc = 0; - if(fc > 10) - fc = 0; - - int size = opt.size() - 1; - if((down & HidNpadButton_Up) || ((held & HidNpadButton_Up) && fc == HOLD_FC)) - { - selected--; - if(selected < 0) - selected = size; - - if((start > selected) && (start > 0)) - start--; - if(size < 15) - start = 0; - if((selected - 14) > start) - start = selected - 14; - } - else if((down & HidNpadButton_Down) || ((held & HidNpadButton_Down) && fc == HOLD_FC)) - { - selected++; - if(selected > size) - selected = 0; - - if((selected > (start + 14)) && ((start + 14) < size)) - start++; - if(selected == 0) - start = 0; - } - else if(down & HidNpadButton_Right) - { - selected += 7; - if(selected > size) - selected = size; - if((selected - 14) > start) - start = selected - 14; - } - else if(down & HidNpadButton_Left) - { - selected -= 7; - if(selected < 0) - selected = 0; - if(selected < start) - start = selected; - } -} - -void ui::menu::draw(const SDL_Color *textClr) -{ - if(opt.size() < 1) - return; - - if(clrAdd) - { - clrSh += 6; - if(clrSh >= 0x72) - clrAdd = false; - } - else - { - clrSh -= 3; - if(clrSh <= 0x00) - clrAdd = true; - } - - int length = 0; - if((opt.size() - 1) < 15) - length = opt.size(); - else - length = start + 15; - - for(int i = start; i < length; i++) - { - if(i == selected) - { - ui::drawBoundBox(x, y + ((i - start) * 36), rW, 36, clrSh); - gfx::drawTextf(18, x + 8, (y + 8) + ((i - start) * 36), ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, opt[i].c_str()); - } - else - gfx::drawTextf(18, x + 8, (y + 8) + ((i - start) * 36), textClr, opt[i].c_str()); - } -} - -void ui::menu::reset() -{ - opt.clear(); - start = 0; - selected = 0; - - fc = 0; -} - -void ui::menu::adjust() -{ - if(selected > (int)opt.size() - 1) - selected = opt.size() - 1; - - if(opt.size() < 14) - start = 0; - else if(opt.size() > 14 && start + 14 > (int)opt.size() - 1) - start = opt.size() - 15; -} - diff --git a/src/ui/miscui.cpp b/src/ui/miscui.cpp index 6989d97..afe2cfe 100644 --- a/src/ui/miscui.cpp +++ b/src/ui/miscui.cpp @@ -20,6 +20,9 @@ static const SDL_Color fillBack = {0x66, 0x66, 0x66, 0xFF}; static const SDL_Color fillLight = {0x00, 0xFF, 0xC5, 0xFF}; static const SDL_Color fillDark = {0x32, 0x50, 0xF0, 0xFF}; +static const SDL_Color menuColorLight = {0x32, 0x50, 0xF0, 0xFF}; +static const SDL_Color menuColorDark = {0x00, 0xFF, 0xC5, 0xFF}; + enum popStates { popRise, @@ -27,11 +30,264 @@ enum popStates popFall }; +//8 +static const std::string loadGlyphArray[] = +{ + "\ue020", "\ue021", "\ue022", "\ue023", + "\ue024", "\ue025", "\ue026", "\ue027" +}; + +void ui::menu::setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW, const unsigned& _fS, const unsigned& _mL) +{ + x = _x; + y = _y; + rW = _rW; + rY = _y; + fSize = _fS; + mL = _mL; + rH = _fS + 24; +} + +void ui::menu::editParam(int _param, unsigned newVal) +{ + switch(_param) + { + case MENU_X: + x = newVal; + break; + + case MENU_Y: + y = newVal; + break; + + case MENU_RECT_WIDTH: + rW = newVal; + break; + + case MENU_FONT_SIZE: + fSize = newVal; + break; + + case MENU_MAX_SCROLL: + mL = newVal; + break; + } +} + +void ui::menu::addOpt(SDL_Texture *_icn, const std::string& add) +{ + ui::menuOpt newOpt; + if((int)gfx::getTextWidth(add.c_str(), fSize) < rW - 56 || rW == 0) + newOpt.txt = add; + else + { + std::string tmp; + for(unsigned i = 0; i < add.length(); ) + { + uint32_t tmpChr = 0; + ssize_t untCnt = decode_utf8(&tmpChr, (uint8_t *)&add.c_str()[i]); + + tmp += add.substr(i, untCnt); + i += untCnt; + if((int)gfx::getTextWidth(tmp.c_str(), fSize) >= rW - 48) + { + newOpt.txt = tmp; + break; + } + } + } + newOpt.icn = _icn; + opt.push_back(newOpt); +} + +void ui::menu::editOpt(int ind, SDL_Texture *_icn, const std::string& ch) +{ + if(!opt[ind].icn && _icn) + opt[ind].icn = _icn; + + opt[ind].txt = ch; +} + +void ui::menu::setOptFunc(unsigned _ind, unsigned _funcbtn, funcPtr _func, void *args) +{ + opt[_ind].func[_funcbtn] = _func; + opt[_ind].argPtr[_funcbtn] = args; +} + +int ui::menu::getOptPos(const std::string& txt) +{ + for(unsigned i = 0; i < opt.size(); i++) + { + if(opt[i].txt == txt) + return i; + } + return -1; +} + + +ui::menu::~menu() +{ + opt.clear(); +} + +void ui::menu::update() +{ + if(!isActive) + return; + + uint64_t down = ui::padKeysDown(); + uint64_t held = ui::padKeysHeld(); + + if(held & HidNpadButton_AnyUp || held & HidNpadButton_AnyDown) + ++fc; + else + fc = 0; + + if(fc > 10) + fc = 0; + + int oldSel = selected; + int mSize = opt.size() - 1, scrL = mL - 1; + if( (down & HidNpadButton_AnyUp) || ((held & HidNpadButton_AnyUp) && fc == 10) ) + { + --selected; + if(selected < 0) + selected = mSize; + + if(mSize > (int)mL) + { + if(start > selected) + --start; + else if(selected - scrL > start) + start = selected - scrL; + } + } + else if( (down & HidNpadButton_AnyDown) || ((held & HidNpadButton_AnyDown) && fc == 10)) + { + ++selected; + if(selected > mSize) + selected = 0; + + if(selected > (start + scrL) && (start + scrL) < mSize) + ++start; + if(selected == 0) + start = 0; + } + else if(down & HidNpadButton_AnyLeft) + { + selected -= scrL / 2; + if(selected < 0) + selected = 0; + if(selected < start) + start = selected; + } + else if(down & HidNpadButton_AnyRight) + { + selected += scrL / 2; + if(selected > mSize) + selected = mSize; + if(selected - scrL > start) + start = selected - scrL; + } + + //func exec + switch(down) + { + case HidNpadButton_A: + if(opt[selected].func[FUNC_A]) + (*opt[selected].func[FUNC_A])(opt[selected].argPtr[FUNC_A]); + break; + + case HidNpadButton_B: + if(opt[selected].func[FUNC_B]) + (*opt[selected].func[FUNC_B])(opt[selected].argPtr[FUNC_B]); + break; + + case HidNpadButton_X: + if(opt[selected].func[FUNC_X]) + (*opt[selected].func[FUNC_X])(opt[selected].argPtr[FUNC_X]); + break; + + case HidNpadButton_Y: + if(opt[selected].func[FUNC_Y]) + (*opt[selected].func[FUNC_Y])(opt[selected].argPtr[FUNC_Y]); + break; + } + + if(selected != oldSel && onChange) + (*onChange)(NULL); + + if(callback) + (*callback)(callbackArgs); +} + +void ui::menu::draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText) +{ + if(opt.size() < 1) + return; + + if(clrAdd) + { + clrSh += 6; + if(clrSh >= 0x72) + clrAdd = false; + } + else + { + clrSh -= 3; + if(clrSh <= 0x00) + clrAdd = true; + } + + for(int i = start; i < (int)opt.size(); i++) + { + if(i == selected) + { + if(isActive) + ui::drawBoundBox(target, x, y + ((i - start) * rH), rW, rH, clrSh); + + gfx::drawRect(target, ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, x + 10, ((y + (rH / 2 - fSize / 2)) + ((i - start) * rH)) - 2, 4, fSize + 4); + if(drawText) + gfx::drawTextf(target, fSize, x + 20, (y + (rH / 2 - fSize / 2)) + ((i - start) * rH), ui::thmID == ColorSetId_Light ? &menuColorLight : &menuColorDark, opt[i].txt.c_str()); + } + else + { + if(drawText) + gfx::drawTextf(target, fSize, x + 20, (y + (rH / 2 - fSize / 2)) + ((i - start) * rH), textClr, opt[i].txt.c_str()); + } + + int w, h; + if(opt[i].icn && SDL_QueryTexture(opt[i].icn, NULL, NULL, &w, &h) == 0) + { + 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 - start) * rH), dW, dH); + } + + } +} + +void ui::menu::reset() +{ + opt.clear(); + start = 0; + selected = 0; + + fc = 0; +} + +void ui::menu::setActive(bool _set) +{ + isActive = _set; +} + void ui::progBar::update(const uint64_t& _prog) { prog = _prog; - width = (float)(((float)prog / (float)max) * (float)maxWidth); + width = (float)(((float)prog / (float)max) * 576); } void ui::progBar::draw(const std::string& text, const std::string& head) @@ -39,24 +295,55 @@ void ui::progBar::draw(const std::string& text, const std::string& head) size_t headWidth = gfx::getTextWidth(head.c_str(), 20); unsigned headX = (1280 / 2) - (headWidth / 2); - ui::drawTextbox(320, 150, 640, 420); - gfx::drawLine(ui::thmID == ColorSetId_Light ? &divLight : &divDark, 320, 206, 959, 206); - gfx::drawRect(&fillBack, 352, 530, 576, 12); - gfx::drawRect(ui::thmID == ColorSetId_Light ? &fillLight : &fillDark, 352, 530, (int)width, 12); - gfx::texDraw(ui::progCovLeft, 352, 530); - gfx::texDraw(ui::progCovRight, 920, 530); + ui::drawTextbox(NULL, 320, 150, 640, 420); + gfx::drawLine(NULL, ui::thmID == ColorSetId_Light ? &divLight : &divDark, 320, 206, 959, 206); + gfx::drawRect(NULL, &fillBack, 352, 530, 576, 12); + gfx::drawRect(NULL, ui::thmID == ColorSetId_Light ? &fillLight : &fillDark, 352, 530, (int)width, 12); + gfx::texDraw(NULL, ui::progCovLeft, 352, 530); + gfx::texDraw(NULL, ui::progCovRight, 920, 530); - - gfx::drawTextf(20, headX, 160, &ui::txtDiag, head.c_str()); - gfx::drawTextfWrap(16, 352, 230, 576, &ui::txtDiag, text.c_str()); + gfx::drawTextf(NULL, 20, headX, 168, &ui::txtDiag, head.c_str()); + gfx::drawTextfWrap(NULL, 16, 352, 230, 576, &ui::txtDiag, text.c_str()); } -void ui::progBar::drawNoDialog(int x, int y) +ui::slideOutPanel::slideOutPanel(int _w, int _h, int _y, funcPtr _draw) { - gfx::drawRect(&fillBack, x, y, maxWidth, 12); - gfx::drawRect(ui::thmID == ColorSetId_Light ? &fillLight : &fillDark, x, y, width, 12); - gfx::texDraw(ui::progCovLeft, x, y); - gfx::texDraw(ui::progCovRight, x + maxWidth - 8, y); + w = _w; + h = _h; + y = _y; + drawFunc = _draw; + panel = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, w, h); + SDL_SetTextureBlendMode(panel, SDL_BLENDMODE_BLEND); + + int getDiv = 99; + while(w % getDiv != 0){ getDiv--; } + slideSpd = getDiv; +} + +ui::slideOutPanel::~slideOutPanel() +{ + SDL_DestroyTexture(panel); +} + +void ui::slideOutPanel::draw(const SDL_Color *backCol) +{ + gfx::clearTarget(panel, backCol); + + if(open && x > 1280 - w) + { + x -= slideSpd; + } + else if(!open && x < 1280) + { + x += slideSpd; + } + + //don't waste time drawing if you can't even see it. + if(x < 1280) + { + (*drawFunc)(panel); + gfx::texDraw(NULL, panel, x, y); + } } void ui::showMessage(const char *head, const char *fmt, ...) @@ -72,17 +359,18 @@ void ui::showMessage(const char *head, const char *fmt, ...) while(true) { - ui::updatePad(); + ui::updateInput(); if(ui::padKeysDown()) break; - ui::drawTextbox(320, 150, 640, 420); - gfx::drawTextf(20, 320 + headX, 168, &ui::txtDiag, head); - gfx::drawTextfWrap(16, 352, 230, 576, &ui::txtDiag, tmp); - gfx::drawTextf(20, 320 + okX, 522, &ui::txtDiag, okt); + ui::drawTextbox(NULL, 320, 150, 640, 420); + gfx::drawTextf(NULL, 20, 320 + headX, 168, &ui::txtDiag, head); + gfx::drawTextfWrap(NULL, 16, 352, 230, 576, &ui::txtDiag, tmp); + gfx::drawTextf(NULL, 20, 320 + okX, 522, &ui::txtDiag, okt); gfx::present(); } + ui::updateInput(); } bool ui::confirm(bool hold, const char *fmt, ...) @@ -106,7 +394,7 @@ bool ui::confirm(bool hold, const char *fmt, ...) while(true) { - ui::updatePad(); + ui::updateInput(); uint64_t down = ui::padKeysDown(); uint64_t held = ui::padKeysHeld(); @@ -161,18 +449,21 @@ bool ui::confirm(bool hold, const char *fmt, ...) if(hold && heldDown) { if(ui::thmID == ColorSetId_Light) - holdClr = {0xFF, 0xFF - holdClrDiff, 0xFF - holdClrDiff, 0xFF}; + holdClr = {0xFF, (uint8_t)(0xFF - holdClrDiff), (uint8_t)(0xFF - holdClrDiff), 0xFF}; else - holdClr = {0x25 + holdClrDiff, 0x00, 0x00, 0xFF}; + holdClr = {(uint8_t)(0x25 + holdClrDiff), 0x00, 0x00, 0xFF}; } - ui::drawTextbox(320, 150, 640, 420); - gfx::drawTextf(20, 320 + headX, 168, &ui::txtDiag, ui::confirmHead.c_str()); - gfx::drawTextf(20, 320 + yesX, 522, &holdClr, yesText.c_str()); - gfx::drawTextf(20, 640 + noX, 522, &ui::txtDiag, ui::nt.c_str()); - gfx::drawTextfWrap(16, 352, 230, 576, &ui::txtDiag, tmp); + ui::drawTextbox(NULL, 320, 150, 640, 420); + gfx::drawTextf(NULL, 20, 320 + headX, 168, &ui::txtDiag, ui::confirmHead.c_str()); + gfx::drawTextf(NULL, 20, 320 + yesX, 522, &holdClr, yesText.c_str()); + gfx::drawTextf(NULL, 20, 640 + noX, 522, &ui::txtDiag, ui::nt.c_str()); + gfx::drawTextfWrap(NULL, 16, 352, 230, 576, &ui::txtDiag, tmp); gfx::present(); } + + ui::updateInput(); + return ret; } @@ -186,40 +477,55 @@ bool ui::confirmDelete(const std::string& p) return confirm(data::holdDel, ui::confDel.c_str(), p.c_str()); } -void ui::drawTextbox(int x, int y, int w, int h) +void ui::drawTextbox(SDL_Texture *target, int x, int y, int w, int h) { //Top - gfx::texDraw(ui::cornerTopLeft, x, y); - gfx::drawRect(&ui::tboxClr, x + 32, y, w - 64, 32); - gfx::texDraw(ui::cornerTopRight, (x + w) - 32, y); + gfx::texDraw(target, ui::cornerTopLeft, x, y); + gfx::drawRect(target, &ui::tboxClr, x + 32, y, w - 64, 32); + gfx::texDraw(target, ui::cornerTopRight, (x + w) - 32, y); //middle - gfx::drawRect(&ui::tboxClr, x, y + 32, w, h - 64); + gfx::drawRect(target, &ui::tboxClr, x, y + 32, w, h - 64); //bottom - gfx::texDraw(ui::cornerBottomLeft, x, (y + h) - 32); - gfx::drawRect(&ui::tboxClr, x + 32, (y + h) - 32, w - 64, 32); - gfx::texDraw(ui::cornerBottomRight, (x + w) - 32, (y + h) - 32); + gfx::texDraw(target, ui::cornerBottomLeft, x, (y + h) - 32); + gfx::drawRect(target, &ui::tboxClr, x + 32, (y + h) - 32, w - 64, 32); + gfx::texDraw(target, ui::cornerBottomRight, (x + w) - 32, (y + h) - 32); } -/*void ui::drawTextboxInvert(tex *target, int x, int y, int w, int h) +void ui::drawBoundBox(SDL_Texture *target, int x, int y, int w, int h, uint8_t clrSh) { - clr temp = ui::tboxClr; - clrInvert(&temp); + SDL_SetRenderTarget(gfx::render, target); + SDL_Color rectClr; - //Top - texDrawInvert(ui::cornerTopLeft, target, x, y); - drawRect(target, x + 32, y, w - 64, 32, temp); - texDrawInvert(ui::cornerTopRight, target, (x + w) - 32, y); + if(ui::thmID == ColorSetId_Light) + rectClr = {0xFD, 0xFD, 0xFD, 0xFF}; + else + rectClr = {0x21, 0x22, 0x21, 0xFF}; - //middle - drawRect(target, x, y + 32, w, h - 64, temp); + gfx::drawRect(target, &rectClr, x + 4, y + 4, w - 8, h - 8); + + rectClr = {0x00,(uint8_t)(0x88 + clrSh), (uint8_t)(0xC5 + (clrSh / 2)), 0xFF}; + + SDL_SetTextureColorMod(mnuTopLeft, rectClr.r, rectClr.g, rectClr.b); + SDL_SetTextureColorMod(mnuTopRight, rectClr.r, rectClr.g, rectClr.b); + SDL_SetTextureColorMod(mnuBotLeft, rectClr.r, rectClr.g, rectClr.b); + SDL_SetTextureColorMod(mnuBotRight, rectClr.r, rectClr.g, rectClr.b); + + //top + gfx::texDraw(target, mnuTopLeft, x, y); + gfx::drawRect(target, &rectClr, x + 4, y, w - 8, 4); + gfx::texDraw(target, mnuTopRight, (x + w) - 4, y); + + //mid + gfx::drawRect(target, &rectClr, x, y + 4, 4, h - 8); + gfx::drawRect(target, &rectClr, (x + w) - 4, y + 4, 4, h - 8); //bottom - texDrawInvert(ui::cornerBottomLeft, target, x, (y + h) - 32); - drawRect(target, x + 32, (y + h) - 32, w - 64, 32, temp); - texDrawInvert(ui::cornerBottomRight, target, (x + w) - 32, (y + h) - 32); -}*/ + gfx::texDraw(target, mnuBotLeft, x, (y + h) - 4); + gfx::drawRect(target, &rectClr, x + 4, (y + h) - 4, w - 8, 4); + gfx::texDraw(target, mnuBotRight, (x + w) - 4, (y + h) - 4); +} void ui::showPopup(unsigned frames, const char *fmt, ...) { @@ -267,7 +573,7 @@ void ui::drawPopup(const uint64_t& down) break; } - drawTextbox(popX, popY, popWidth, 64); - gfx::drawTextf(24, popX + 16, popY + 20, &ui::txtDiag, popText.c_str()); + drawTextbox(NULL, popX, popY, popWidth, 64); + gfx::drawTextf(NULL, 24, popX + 16, popY + 20, &ui::txtDiag, popText.c_str()); } diff --git a/src/ui/ttl.cpp b/src/ui/ttl.cpp new file mode 100644 index 0000000..25142ac --- /dev/null +++ b/src/ui/ttl.cpp @@ -0,0 +1,347 @@ +#include "ui.h" +#include "ttl.h" +#include "file.h" +#include "util.h" + +class titleTile +{ + public: + titleTile(unsigned _w, unsigned _h, bool _fav, SDL_Texture *_icon) + { + w = _w; + h = _h; + wS = _w; + hS = _h; + fav = _fav; + icon = _icon; + } + + void draw(SDL_Texture *target, int x, int y, bool sel); + + private: + unsigned w, h, wS, hS; + bool fav = false; + SDL_Texture *icon; +}; + +static uint8_t clrShft = 0; +static bool clrAdd = true; +static int selRectX = 38, selRectY = 38; +static int x = 34, y = 69, ttlHelpX = 0; +static std::vector titleList; +static ui::menu *ttlOpts; +static ui::slideOutPanel *ttlOptsPanel, *infoPanel; +static std::string infoPanelString; + +static void ttlOptsCallback(void *a) +{ + switch(ui::padKeysDown()) + { + case HidNpadButton_B: + ttlOpts->setActive(false); + ttlOptsPanel->closePanel(); + ui::updateInput(); + break; + } +} + +static void ttlOptsPanelDraw(void *a) +{ + SDL_Texture *panel = (SDL_Texture *)a; + ttlOpts->draw(panel, &ui::txtCont, true); +} + +static void ttlOptsShowInfoPanel(void *a) +{ + ttlOpts->setActive(false); + ttlOptsPanel->closePanel(); + infoPanelString = util::getInfoString(data::curUser, data::curData.saveID); + infoPanel->openPanel(); +} + +static void ttlOptsBlacklistTitle(void *a) +{ + std::string title = data::getTitleNameByTID(data::curData.saveID); + if(ui::confirm(false, ui::confBlacklist.c_str(), title.c_str())) + { + data::blacklistAdd(data::curData.saveID); + ui::setupTiles(NULL); + } +} + +static void ttlOptsResetSaveData(void *a) +{ + std::string title = data::getTitleNameByTID(data::curData.saveID); + if(ui::confirm(data::holdDel, ui::saveDataReset.c_str(), title.c_str()) && fs::mountSave(data::curData.saveInfo)) + { + fs::delDir("sv:/"); + fsdevCommitDevice("sv:/"); + fs::unmountSave(); + ui::showPopup(POP_FRAME_DEFAULT, ui::saveDataResetSuccess.c_str(), title.c_str()); + } +} + +static void ttlOptsDeleteSaveData(void *a) +{ + FsSaveDataAttribute attr; + attr.application_id = data::curData.saveID; + attr.uid = data::curUser.getUID(); + attr.system_save_data_id = 0; + attr.save_data_type = data::curData.saveInfo.save_data_type; + attr.save_data_rank = data::curData.saveInfo.save_data_rank; + attr.save_data_index = data::curData.saveInfo.save_data_index; + + std::string title = data::getTitleNameByTID(data::curData.saveID); + if(ui::confirm(data::holdDel, ui::confEraseNand.c_str(), title.c_str()) && R_SUCCEEDED(fsDeleteSaveDataFileSystemBySaveDataAttribute(FsSaveDataSpaceId_User, &attr))) + { + data::loadUsersTitles(false); + if(data::curUser.titleInfo.size() == 0) + { + //Kick back to user + ttlOptsPanel->closePanel();//JIC + ui::usrMenuSetActive(true); + ui::changeState(USR_SEL); + } + else if(data::selData > (int)data::curUser.titleInfo.size() - 1) + data::selData = data::curUser.titleInfo.size() - 1; + + ui::setupTiles(NULL); + ui::showPopup(POP_FRAME_DEFAULT, ui::saveDataDeleteSuccess.c_str(), title.c_str()); + } +} + +static void infoPanelDraw(void *a) +{ + SDL_Texture *panel = (SDL_Texture *)a; + gfx::texDraw(panel, data::getTitleIconByTID(data::curData.saveID), 77, 32); + gfx::drawTextfWrap(panel, 18, 32, 320, 362, &ui::txtCont, infoPanelString.c_str()); +} + +void ui::ttlInit() +{ + ttlHelpX = 1220 - gfx::getTextWidth(ui::titleHelp.c_str(), 18); + + ttlOpts = new ui::menu; + ttlOpts->setParams(10, 32, 390, 18, 8); + + ttlOptsPanel = new ui::slideOutPanel(410, 720, 0, ttlOptsPanelDraw); + ttlOpts->setCallback(ttlOptsCallback, NULL); + ui::addPanel(ttlOptsPanel); + + infoPanel = new ui::slideOutPanel(410, 720, 0, infoPanelDraw); + ui::addPanel(infoPanel); + + ttlOpts->setActive(false); + ttlOpts->addOpt(NULL, ui::titleOptString[0]); + ttlOpts->setOptFunc(0, FUNC_A, ttlOptsShowInfoPanel, NULL); + ttlOpts->addOpt(NULL, ui::titleOptString[1]); + ttlOpts->setOptFunc(1, FUNC_A, ttlOptsBlacklistTitle, NULL); + ttlOpts->addOpt(NULL, ui::titleOptString[2]); + ttlOpts->setOptFunc(2, FUNC_A, ttlOptsResetSaveData, NULL); + ttlOpts->addOpt(NULL, ui::titleOptString[3]); + ttlOpts->setOptFunc(3, FUNC_A, ttlOptsDeleteSaveData, NULL); +} + +void ui::ttlExit() +{ + delete ttlOptsPanel; + delete ttlOpts; + delete infoPanel; +} + +void ui::setupTiles(void *) +{ + titleList.clear(); + int infoSize = data::curUser.titleInfo.size(); + for(int i = 0; i < infoSize; i++) + { + uint64_t sid = data::curUser.titleInfo[i].saveID; + SDL_Texture *iconPtr = data::getTitleIconByTID(sid); + bool fav = data::isFavorite(sid); + titleList.emplace_back(128, 128, fav, iconPtr); + } +} + +void ui::ttlReset() +{ + clrShft = 0; + clrAdd = true; + selRectX = 38; + selRectY = 38; + x = 34; + y = 69; + //Reset data + data::selData = 0; +} + +static inline void updateTitleScroll() +{ + if(selRectY > 264) + y -= 48; + else if(selRectY > 144) + y -= 24; + else if(selRectY < -82) + y += 48; + else if(selRectY < 38) + y += 24; +} + +void ui::ttlUpdate() +{ + ttlOpts->update(); + + if(ttlOptsPanel->isOpen() || infoPanel->isOpen()) + return; + + uint64_t down = ui::padKeysDown(); + + switch(down) + { + case HidNpadButton_A: + if(fs::mountSave(data::curData.saveInfo)) + { + fldInit(); + ui::changeState(FLD_SEL); + } + else + ui::showPopup(POP_FRAME_DEFAULT, "Failed to Mount save!"); + break; + + case HidNpadButton_B: + ui::usrMenuSetActive(true); + ui::changeState(USR_SEL); + break; + + case HidNpadButton_X: + ttlOpts->setActive(true); + ttlOptsPanel->openPanel(); + break; + + case HidNpadButton_Y: + { + uint64_t sid = data::curData.saveID; + data::favoriteTitle(sid); + setupTiles(NULL); + if(data::isFavorite(sid)) + data::selData = data::getTitleIndexInUser(data::curUser, sid); + } + break; + + case HidNpadButton_StickLUp: + case HidNpadButton_Up: + data::selData -= 7; + if(data::selData < 0) + data::selData = 0; + break; + + case HidNpadButton_StickLDown: + case HidNpadButton_Down: + data::selData += 7; + if(data::selData > (int)data::curUser.titleInfo.size() - 1) + data::selData = data::curUser.titleInfo.size() - 1; + break; + + case HidNpadButton_StickLLeft: + case HidNpadButton_Left: + if(data::selData > 0) + --data::selData; + break; + + case HidNpadButton_StickLRight: + case HidNpadButton_Right: + if(data::selData < (int)data::curUser.titleInfo.size() - 1) + ++data::selData; + break; + + case HidNpadButton_L: + if(data::selData - 21 > 0) + data::selData -= 21; + else + data::selData = 0; + break; + + case HidNpadButton_R: + if(data::selData + 21 < (int)data::curUser.titleInfo.size()) + data::selData += 21; + else + data::selData = data::curUser.titleInfo.size() - 1; + break; + } +} + +void ui::ttlDraw(SDL_Texture *target) +{ + updateTitleScroll(); + + if(clrAdd) + { + clrShft += 6; + if(clrShft >= 0x72) + clrAdd = false; + } + else + { + clrShft -= 3; + if(clrShft <= 0) + clrAdd = true; + } + + int totalTiles = titleList.size(); + int selX = 0, selY = 0; + for(int tY = y, i = 0; i < totalTiles; tY += 144) + { + int endRow = i + 7; + for(int tX = x; i < endRow; tX += 144, i++) + { + if(i >= totalTiles) + break; + + if(i == data::selData && (ui::mstate == TTL_SEL|| ui::mstate == FLD_SEL)) + { + //save x and y for selected for later so it's drawn on top. + //I can't find anyway to change the Z for SDL. + selX = tX; + selY = tY; + selRectX = tX - 24; + selRectY = tY - 24; + } + else + titleList[i].draw(target, tX, tY, false); + } + } + + if(ui::mstate == TTL_SEL || ui::mstate == FLD_SEL) + { + //Draw selected after so it's on top + ui::drawBoundBox(target, selRectX, selRectY, 176, 176, clrShft); + titleList[data::selData].draw(target, selX, selY, true); + if(ui::mstate == TTL_SEL) + gfx::drawTextf(NULL, 18, ttlHelpX, 673, &ui::txtCont, ui::titleHelp.c_str()); + } +} + +//Todo make less hardcoded +void titleTile::draw(SDL_Texture *target, int x, int y, bool sel) +{ + if(sel) + { + unsigned xScale = w * 1.28, yScale = w * 1.28; + if(wS < xScale) + wS += 18; + if(hS < yScale) + hS += 18; + } + else + { + if(wS > w) + wS -= 18; + if(hS > h) + hS -= 18; + } + + int dX = x - ((wS - w) / 2); + int dY = y - ((hS - h) / 2); + gfx::texDrawStretch(target, icon, dX, dY, wS, hS); + if(fav) + gfx::drawTextf(target, 20, dX + 8, dY + 8, &ui::heartColor, "♥"); +} diff --git a/src/ui/ttlsel.cpp b/src/ui/ttlsel.cpp deleted file mode 100644 index 0afc8ee..0000000 --- a/src/ui/ttlsel.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include -#include - -#include "data.h" -#include "ui.h" -#include "uiupdate.h" -#include "file.h" -#include "util.h" - -//Where to start in titles -static int start = 0; - -//Color shift for rect -static uint8_t clrShft = 0; -//Whether or not we're adding or subtracting from clrShft -static bool clrAdd = true; - -//Selected rectangle X and Y. -static unsigned selRectX = 66, selRectY = 94; - -static inline void reset() -{ - start = 0; - selRectX = 66; - selRectY = 94; - data::selData = 0; -} - -void ui::drawTitleMenu() -{ - if(clrAdd) - { - clrShft += 6; - if(clrShft >= 0x72) - clrAdd = false; - } - else - { - clrShft -= 3; - if(clrShft <= 0) - clrAdd = true; - } - - unsigned x = 70, y = 98; - - unsigned endTitle = start + 32; - if(start + 32 > (int)data::curUser.titles.size()) - endTitle = data::curUser.titles.size(); - - //draw Rect so it's always behind icons - drawBoundBox(selRectX, selRectY, 140, 140, clrShft); - - for(unsigned i = start; i < endTitle; y += 136) - { - unsigned endRow = i + 8; - for(unsigned tX = x; i < endRow; i++, tX += 144) - { - if(i == endTitle) - break; - - if((int)i == data::selData) - { - selRectX = tX - 6; - selRectY = y - 6; - - unsigned titleWidth = gfx::getTextWidth(data::curData.getTitle().c_str(), 18); - int rectWidth = titleWidth + 32, rectX = (tX + 64) - (rectWidth / 2); - if(rectX < 16) - rectX = 16; - else if(rectX + rectWidth > 1264) - rectX = 1264 - rectWidth; - - ui::drawTextbox(rectX, y - 50, rectWidth, 38); - gfx::drawTextf(18, rectX + 16, y - 40, &ui::txtDiag, data::curData.getTitle().c_str()); - } - if(data::curUser.titles[i].getFav()) - data::curUser.titles[i].drawIconFav(false, tX, y); - else - data::curUser.titles[i].drawIcon(false, tX, y); - } - } -} - -void ui::updateTitleMenu(const uint64_t& down, const uint64_t& held) -{ - switch(down) - { - case HidNpadButton_A: - if(fs::mountSave(data::curUser, data::curData)) - { - folderMenuPrepare(data::curUser, data::curData); - ui::folderMenuInfo = util::getInfoString(data::curUser, data::curData); - ui::changeState(FLD_SEL); - } - break; - - case HidNpadButton_B: - reset(); - ui::changeState(USR_SEL); - break; - - case HidNpadButton_X: - data::favoriteTitle(data::curData); - break; - - case HidNpadButton_Y: - fs::dumpAllUserSaves(data::curUser); - break; - - case HidNpadButton_L: - if(--data::selUser < 0) - data::selUser = data::users.size() - 1; - reset(); - ui::showPopup(POP_FRAME_DEFAULT, data::curUser.getUsername().c_str()); - break; - - case HidNpadButton_R: - if(++data::selUser == (int)data::users.size()) - data::selUser = 0; - reset(); - ui::showPopup(POP_FRAME_DEFAULT, data::curUser.getUsername().c_str()); - break; - - case HidNpadButton_ZR: - if(data::curData.getType() != FsSaveDataType_System && confirm(true, ui::confEraseNand.c_str(), data::curData.getTitle().c_str())) - { - fsDeleteSaveDataFileSystemBySaveDataSpaceId(FsSaveDataSpaceId_User, data::curData.getSaveID()); - data::loadUsersTitles(false); - data::selData = 0; - } - break; - - case HidNpadButton_Minus: - if(ui::confirm(false, ui::confBlacklist.c_str(), data::curUser.titles[data::selData].getTitle().c_str())) - data::blacklistAdd(data::curData); - break; - - case HidNpadButton_StickLUp: - case HidNpadButton_Up: - data::selData -= 8; - if(data::selData < 0) - data::selData = 0; - break; - - case HidNpadButton_StickLDown: - case HidNpadButton_Down: - data::selData += 8; - if(data::selData > (int)data::curUser.titles.size() - 1) - data::selData = data::curUser.titles.size() - 1; - break; - - case HidNpadButton_StickLLeft: - case HidNpadButton_Left: - if(data::selData > 0) - --data::selData; - break; - - case HidNpadButton_StickLRight: - case HidNpadButton_Right: - if(data::selData < (int)data::curUser.titles.size() - 1) - ++data::selData; - break; - } - - if(data::selData < start) - start -= 8; - else if(data::selData - start >= 32) - start += 8; -} - diff --git a/src/ui/txtui.cpp b/src/ui/txtui.cpp deleted file mode 100644 index 525f64c..0000000 --- a/src/ui/txtui.cpp +++ /dev/null @@ -1,474 +0,0 @@ -#include -#include -#include -#include -#include - -#include "ui.h" -#include "data.h" -#include "file.h" -#include "util.h" - -static ui::menu userMenu, titleMenu, exMenu, optMenu; -extern ui::menu folderMenu; - -void ui::textUserPrep() -{ - userMenu.reset(); - - userMenu.setParams(76, 98, 310); - - for(unsigned i = 0; i < data::users.size(); i++) - userMenu.addOpt(data::users[i].getUsername()); -} - -void ui::textTitlePrep(data::user& u) -{ - titleMenu.reset(); - titleMenu.setParams(76, 98, 310); - - for(unsigned i = 0; i < u.titles.size(); i++) - { - if(u.titles[i].getFav()) - titleMenu.addOpt("♥ " + u.titles[i].getTitle()); - else - titleMenu.addOpt(u.titles[i].getTitle()); - } -} - -void ui::textUserMenuUpdate(const uint64_t& down, const uint64_t& held) -{ - userMenu.handleInput(down, held); - - data::selUser = userMenu.getSelected(); - - switch(down) - { - case HidNpadButton_A: - if(data::curUser.titles.size() > 0) - { - ui::textTitlePrep(data::curUser); - ui::changeState(TXT_TTL); - } - else - ui::showPopup(POP_FRAME_DEFAULT, ui::noSavesFound.c_str(), data::curUser.getUsername().c_str()); - break; - - case HidNpadButton_X: - ui::textMode = false; - ui::changeState(USR_SEL); - break; - - case HidNpadButton_Y: - { - bool cont = true; - for(unsigned i = 0; i < data::users.size() - 2; i++) - { - if(cont) - cont = fs::dumpAllUserSaves(data::users[i]); - } - } - break; - - case HidNpadButton_R: - util::checkForUpdate(); - break; - - case HidNpadButton_ZR: - ui::changeState(EX_MNU); - break; - - case HidNpadButton_Minus: - ui::changeState(OPT_MNU); - break; - } -} - -void ui::drawTextUserMenu() -{ - userMenu.draw(&ui::txtCont); -} - -void ui::textTitleMenuUpdate(const uint64_t& down, const uint64_t& held) -{ - titleMenu.handleInput(down, held); - - data::selData = titleMenu.getSelected(); - - switch(down) - { - case HidNpadButton_A: - if(fs::mountSave(data::curUser, data::curData)) - { - folderMenuPrepare(data::curUser, data::curData); - ui::folderMenuInfo = util::getInfoString(data::curUser, data::curData); - ui::changeState(TXT_FLD); - } - break; - - case HidNpadButton_B: - ui::changeState(TXT_USR); - break; - - case HidNpadButton_X: - data::favoriteTitle(data::curData); - textTitlePrep(data::curUser); - break; - - case HidNpadButton_Y: - fs::dumpAllUserSaves(data::curUser); - break; - - case HidNpadButton_L: - if(--data::selUser < 0) - data::selUser = data::users.size() - 1; - ui::textTitlePrep(data::curUser); - ui::showPopup(POP_FRAME_DEFAULT, data::curUser.getUsername().c_str()); - break; - - case HidNpadButton_R: - if(++data::selUser == (int)data::users.size()) - data::selUser = 0; - ui::textTitlePrep(data::curUser); - ui::showPopup(POP_FRAME_DEFAULT, data::curUser.getUsername().c_str()); - break; - - case HidNpadButton_ZR: - if(data::curData.getType() != FsSaveDataType_System && confirm(true, ui::confEraseNand.c_str(), data::curData.getTitle().c_str())) - { - fsDeleteSaveDataFileSystemBySaveDataSpaceId(FsSaveDataSpaceId_User, data::curData.getSaveID()); - data::loadUsersTitles(false); - data::selData = 0; - } - break; - - case HidNpadButton_Minus: - if(ui::confirm(false, ui::confBlacklist.c_str(), data::curUser.titles[data::selData].getTitle().c_str())) - data::blacklistAdd(data::curData); - break; - } -} - -void ui::drawTextTitleMenu() -{ - titleMenu.draw(&ui::txtCont); -} - -void ui::textFolderMenuUpdate(const uint64_t& down, const uint64_t& held) -{ - folderMenu.handleInput(down, held); - - switch(down) - { - case HidNpadButton_A: - if(folderMenu.getSelected() == 0) - ui::createNewBackup(held); - else - ui::overwriteBackup(folderMenu.getSelected() - 1); - break; - - case HidNpadButton_B: - fs::unmountSave(); - fs::freePathFilters(); - ui::changeState(TXT_TTL); - break; - - case HidNpadButton_X: - if(folderMenu.getSelected() > 0) - ui::deleteBackup(folderMenu.getSelected() - 1); - break; - - case HidNpadButton_Y: - if(folderMenu.getSelected() > 0) - ui::restoreBackup(folderMenu.getSelected() - 1); - break; - - case HidNpadButton_ZR: - if(data::curData.getType() != FsSaveDataType_System && confirm(true, ui::confEraseFolder.c_str(), data::curData.getTitle().c_str())) - { - fs::delDir("sv:/"); - fsdevCommitDevice("sv"); - } - break; - - case HidNpadButton_Minus: - advModePrep("sv:/", data::curData.getType(), true); - ui::changeState(ADV_MDE); - break; - } -} - -void ui::drawTextFolderMenu() -{ - titleMenu.draw(&ui::txtCont); - folderMenu.draw(&ui::txtCont); -} - -void ui::exMenuPrep() -{ - exMenu.reset(); - exMenu.setParams(76, 98, 310); - for(unsigned i = 0; i < 11; i++) - exMenu.addOpt(ui::exMenuStr[i]); -} - -void ui::updateExMenu(const uint64_t& down, const uint64_t& held) -{ - exMenu.handleInput(down, held); - - if(down & HidNpadButton_A) - { - fsdevUnmountDevice("sv"); - FsFileSystem sv; - data::curData.setType(FsSaveDataType_System); - switch(exMenu.getSelected()) - { - case 0: - data::curData.setType(FsSaveDataType_Bcat); - advModePrep("sdmc:/", data::curData.getType(), false); - ui::changeState(ADV_MDE); - break; - - case 1: - fsdevUnmountDevice("sv"); - fsOpenBisFileSystem(&sv, FsBisPartitionId_CalibrationFile, ""); - fsdevMountDevice("prodInfo-f", sv); - advModePrep("profInfo-f:/", FsSaveDataType_System, false); - ui::changeState(ADV_MDE); - break; - - case 2: - fsOpenBisFileSystem(&sv, FsBisPartitionId_SafeMode, ""); - fsdevMountDevice("safe", sv); - advModePrep("safe:/", FsSaveDataType_System, false); - ui::changeState(ADV_MDE); - break; - - case 3: - fsOpenBisFileSystem(&sv, FsBisPartitionId_System, ""); - fsdevMountDevice("sys", sv); - advModePrep("sys:/", FsSaveDataType_System, false); - ui::changeState(ADV_MDE); - break; - - case 4: - fsOpenBisFileSystem(&sv, FsBisPartitionId_User, ""); - fsdevMountDevice("user", sv); - advModePrep("user:/", FsSaveDataType_System, false); - ui::changeState(ADV_MDE); - break; - - case 5: - { - fsOpenBisFileSystem(&sv, FsBisPartitionId_System, ""); - fsdevMountDevice("sv", sv); - std::string delPath = "sv:/Contents/placehld/"; - - fs::dirList plcHld(delPath); - for(unsigned i = 0; i < plcHld.getCount(); i++) - { - std::string fullPath = delPath + plcHld.getItem(i); - std::remove(fullPath.c_str()); - } - fsdevUnmountDevice("sv"); - - if(ui::confirm(false, "Restart?")) - { - bpcInitialize(); - bpcRebootSystem(); - } - } - break; - - case 6: - { - std::string idStr = util::getStringInput("0100000000000000", "Enter Process ID", 18, 0, NULL); - if(!idStr.empty()) - { - uint64_t termID = std::strtoull(idStr.c_str(), NULL, 16); - if(R_SUCCEEDED(pmshellTerminateProgram(termID))) - ui::showMessage("Success!", "Process %s successfully shutdown.", idStr.c_str()); - } - } - break; - - case 7: - { - std::string idStr = util::getStringInput("8000000000000000", "Enter Sys Save ID", 18, 0, NULL); - uint64_t mountID = std::strtoull(idStr.c_str(), NULL, 16); - if(R_SUCCEEDED(fsOpen_SystemSaveData(&sv, FsSaveDataSpaceId_System, mountID, (AccountUid) {0}))) - { - fsdevMountDevice("sv", sv); - advModePrep("sv:/", data::curData.getType(), true); - ui::changeState(ADV_MDE); - } - } - break; - - case 8: - data::loadUsersTitles(true); - break; - - case 9: - { - FsFileSystem tromfs; - //Result res = romfsMountFromCurrentProcess("tromfs"); << Works too, but is kinda weird - if(R_SUCCEEDED(fsOpenDataFileSystemByCurrentProcess(&tromfs))) - { - fsdevMountDevice("tromfs", tromfs); - advModePrep("tromfs:/", FsSaveDataType_Account, false); - ui::changeState(ADV_MDE); - } - } - break; - - case 10: - { - fs::logClose(); - remove(std::string(fs::getWorkDir() + "log.txt").c_str()); - std::string zipName = "JKSV - " + util::getDateTime(util::DATE_FMT_ASC) + ".zip"; - zipFile jksv = zipOpen(std::string("sdmc:/" + zipName).c_str(), 0); - fs::copyDirToZip(fs::getWorkDir(), &jksv); - zipClose(jksv, NULL); - rename(std::string("sdmc:/" + zipName).c_str(), std::string(fs::getWorkDir() + zipName).c_str()); - fs::logOpen(); - } - break; - } - } - else if(down & HidNpadButton_B) - { - fsdevUnmountDevice("sv"); - ui::changeState(ui::textMode ? TXT_USR : USR_SEL); - prevState = USR_SEL; - } -} - -void ui::drawExMenu() -{ - exMenu.draw(&ui::txtCont); -} - -static inline void switchBool(bool& sw) -{ - sw ? sw = false : sw = true; -} - -static inline std::string getBoolText(bool b) -{ - return b ? ui::on : ui::off; -} - -static inline void changeSort() -{ - if(++data::sortType > 2) - data::sortType = 0; -} - -void ui::optMenuInit() -{ - optMenu.setParams(76, 98, 310); - for(unsigned i = 0; i < 15; i++) - optMenu.addOpt(ui::optMenuStr[i]); -} - -void ui::updateOptMenu(const uint64_t& down, const uint64_t& held) -{ - optMenu.handleInput(down, held); - - //Update Menu Options to reflect changes - optMenu.editOpt(0, optMenuStr[0] + getBoolText(data::incDev)); - optMenu.editOpt(1, optMenuStr[1] + getBoolText(data::autoBack)); - optMenu.editOpt(2, optMenuStr[2] + getBoolText(data::ovrClk)); - optMenu.editOpt(3, optMenuStr[3] + getBoolText(data::holdDel)); - optMenu.editOpt(4, optMenuStr[4] + getBoolText(data::holdRest)); - optMenu.editOpt(5, optMenuStr[5] + getBoolText(data::holdOver)); - optMenu.editOpt(6, optMenuStr[6] + getBoolText(data::forceMount)); - optMenu.editOpt(7, optMenuStr[7] + getBoolText(data::accSysSave)); - optMenu.editOpt(8, optMenuStr[8] + getBoolText(data::sysSaveWrite)); - optMenu.editOpt(9, optMenuStr[9] + getBoolText(ui::textMode)); - optMenu.editOpt(10, optMenuStr[10] + getBoolText(data::directFsCmd)); - optMenu.editOpt(11, optMenuStr[11] + getBoolText(data::skipUser)); - optMenu.editOpt(12, optMenuStr[12] + getBoolText(data::zip)); - optMenu.editOpt(13, optMenuStr[13] + ui::sortString[data::sortType]); - optMenu.editOpt(14, optMenuStr[14] + getBoolText(data::langOverride)); - - - if(down & HidNpadButton_A) - { - switch(optMenu.getSelected()) - { - case 0: - switchBool(data::incDev); - break; - - case 1: - switchBool(data::autoBack); - break; - - case 2: - switchBool(data::ovrClk); - break; - - case 3: - switchBool(data::holdDel); - break; - - case 4: - switchBool(data::holdRest); - break; - - case 5: - switchBool(data::holdOver); - break; - - case 6: - switchBool(data::forceMount); - break; - - case 7: - switchBool(data::accSysSave); - break; - - case 8: - switchBool(data::sysSaveWrite); - break; - - case 9: - switchBool(ui::textMode); - break; - - case 10: - switchBool(data::directFsCmd); - break; - - case 11: - switchBool(data::skipUser); - break; - - case 12: - switchBool(data::zip); - break; - - case 13: - changeSort(); - data::loadUsersTitles(false); - break; - - case 14: - switchBool(data::langOverride); - break; - } - } - else if(down & HidNpadButton_X) - data::restoreDefaultConfig(); - else if(down & HidNpadButton_B) - ui::changeState(ui::textMode ? TXT_USR : USR_SEL); -} - -void ui::drawOptMenu() -{ - optMenu.draw(&ui::txtCont); - gfx::drawTextfWrap(18, 466, 98, 730, &ui::txtCont, ui::optMenuExp[optMenu.getSelected()].c_str()); -} - diff --git a/src/ui/uistr.cpp b/src/ui/uistr.cpp index 2c26103..6fe2d58 100644 --- a/src/ui/uistr.cpp +++ b/src/ui/uistr.cpp @@ -1,17 +1,24 @@ #include +#include +#include "file.h" #include "uistr.h" -//8 -const std::string ui::loadGlyphArray[8] = +//Map to associate external string names to unsigned ints for switch case. +static std::unordered_map uistrdef = { - "\ue020", "\ue021", "\ue022", "\ue023", - "\ue024", "\ue025", "\ue026", "\ue027" + {"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::string ui::author = "NULL"; -std::string ui::userHelp = "[A] Select [Y] Dump All [X] UI Mode [R] Update [-] Options [ZR] Extras"; -std::string ui::titleHelp = "[A] Select [L][R] Change User [Y] Dump All [X] Favorite [-] BlackList [ZR] Erase [B] Back"; +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 = "[-] File Mode [L]/[R]+[A] Auto [A] Backup [Y] Restore [X] Delete Selected [ZR] Erase [B] Back"; std::string ui::optHelp = "[A] Toggle [X] Defaults [B] Back"; std::string ui::yt = "Yes [A]", ui::nt = "No [B]"; @@ -24,68 +31,183 @@ 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::confEraseFolder = "*WARNING*: This *will* delete the current save data for #%s# *from your system*! 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[6] = -{ - "Copy to ", - "Delete", - "Rename", - "Make Dir", - "Properties", - "Close" -}; -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[15] = -{ - "Include Dev Sv: ", - "AutoBackup: ", - "Overclock: ", - "Hold to Delete: ", - "Hold to Restore: ", - "Hold to Overwrite: ", - "Force Mount: ", - "Account Sys. Saves: ", - "Write to Sys. Saves: ", - "Text UI Mode: ", - "Direct FS Cmd: ", - "Skip User Select: ", - "Export to ZIP: ", - "Sort: ", - "Language Override: " -}; -std::string ui::optMenuExp[15] = -{ - "Includes Device Save data in user accounts.", - "Automatically creates a save backup before restoring a save.", - "Applies a small CPU over clock to 1224Mhz at boot. This is the same speed developer units run at.", - "Whether or not holding [A] is required when deleting folders and files.", - "Whether or not holding [A] is required when restoring save data.", - "Whether or not holding [A] is required when overwriting saves on SD.", - "When enabled, JKSV will only load and show save data that can be opened. When disabled, everything found will be shown.", - "When enabled, system save data tied to accounts will be shown.", - "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!*", - "Changes the UI to be text menu based like the original JKSM for 3DS.", - "Directly uses the Switch's FS commands to copy files instead of stdio.", - "Skips the user selection screen and jumps directly to the first user account found.", - "Exports saves to ZIP files.", - "Changes the way titles are sorted and listed.", - "Forces English to be used regardless of system language." -}; +std::string ui::advMenuStr[6] = { "Copy to ", "Delete", "Rename", "Make Dir", "Properties", "Close" }; +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[15] = { "Include Device Saves: ", "AutoBackup: ", "Overclock: ", "Hold to Delete: ", "Hold to Restore: ", "Hold to Overwrite: ", "Force Mount: ", "Account Sys. Saves: ", "Write to Sys. Saves: ", "Text UI Mode: ", "Direct FS Cmd: ", "Skip User Select: ", "Export to ZIP: ", "Language Override: ", "Sort: "}; std::string ui::holdingText[3] = { "(Hold) ", "(Keep Holding) ", "(Almost there!) " }; std::string ui::sortString[3] = { "Alphabetical", "Time Played", "Last Played" }; +std::string ui::usrOptString[1] = { "Create Save Data" }; +std::string ui::titleOptString[4] = {"Information", "Blacklist", "Reset Save Data", "Delete Save Filesystem"}; + +void ui::loadTrans() +{ + bool transFile = fs::fileExists(fs::getWorkDir() + "trans.txt"); + if(!transFile && data::sysLang == SetLanguage_ENUS) + return;//Don't bother loading from file. It serves as a translation guide + + std::string file; + if(transFile) + file = fs::getWorkDir() + "trans.txt"; + else + { + file = "romfs:/lang/"; + switch(data::sysLang) + { + 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; + } + } + + fs::dataFile lang(file); + while(lang.readNextLine(true)) + { + switch(uistrdef[lang.getName()]) + { + 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: + ui::showMessage("*Translation File Error:*", "On Line: %s\n*%s* is not a known or valid string name.", lang.getLine(), lang.getName()); + break; + } + } +} + diff --git a/src/ui/usr.cpp b/src/ui/usr.cpp new file mode 100644 index 0000000..b0287be --- /dev/null +++ b/src/ui/usr.cpp @@ -0,0 +1,237 @@ +#include +#include +#include + +#include "file.h" +#include "data.h" +#include "ui.h" +#include "util.h" +#include "type.h" + +#include "usr.h" +#include "ttl.h" + +//Main menu/Users + options, folder +static ui::menu *usrMenu, *usrOptMenu, *saveCreateMenu; +static ui::slideOutPanel *usrOptPanel, *saveCreatePanel; + +//This stores save ids to match with saveCreateMenu +//Probably needs/should be changed +static std::vector sids; + +static unsigned optsPos = 0, extPos = 0, usrHelpX = 0; + +fs::backupArgs backargs; + +static void onMainChange(void *a) +{ + if(usrMenu->getSelected() < (int)data::users.size()) + { + data::selUser = usrMenu->getSelected(); + ui::ttlReset(); + ui::setupTiles(NULL); + } +} + +static void toOPT(void *a) +{ + ui::changeState(OPT_MNU); + ui::usrMenuSetActive(false); +} + +static void toEXT(void *a) +{ + ui::changeState(EX_MNU); + ui::usrMenuSetActive(false); +} + +static void toMAIN(void *a) +{ + if(ui::padKeysDown() & HidNpadButton_B) + { + ui::changeState(USR_SEL); + ui::usrMenuSetActive(true); + } +} + +static void usrOptCallback(void *a) +{ + switch(ui::padKeysDown()) + { + case HidNpadButton_B: + usrOptPanel->closePanel(); + usrMenu->setActive(true); + usrOptMenu->setActive(false); + break; + } +} + +static void saveCreateCallback(void *a) +{ + switch(ui::padKeysDown()) + { + case HidNpadButton_B: + usrOptMenu->setActive(true); + saveCreateMenu->setActive(false); + saveCreatePanel->closePanel(); + usrOptPanel->openPanel(); + break; + } +} + +static void usrOptSaveCreate(void *a) +{ + ui::updateInput(); + usrOptMenu->setActive(false); + saveCreateMenu->setActive(true); + usrOptPanel->closePanel(); + saveCreatePanel->openPanel(); +} + +static void usrOptPanelDraw(void *a) +{ + SDL_Texture *panel = (SDL_Texture *)a; + usrOptMenu->draw(panel, &ui::txtCont, true); +} + +static void saveCreatePanelDraw(void *a) +{ + SDL_Texture *panel = (SDL_Texture *)a; + saveCreateMenu->draw(panel, &ui::txtCont, true); +} + +static void createSaveData(void *a) +{ + ui::menu *in = (ui::menu *)a; + uint64_t sid = sids[in->getSelected()]; + data::titleInfo *create = data::getTitleInfoByTID(sid); + + FsSaveDataAttribute attr; + memset(&attr, 0, sizeof(FsSaveDataAttribute)); + attr.application_id = sid; + attr.uid = data::curUser.getUID(); + attr.system_save_data_id = 0; + attr.save_data_type = FsSaveDataType_Account; + attr.save_data_rank = 0; + attr.save_data_index = 0; + + FsSaveDataCreationInfo svCreate; + memset(&svCreate, 0, sizeof(FsSaveDataCreationInfo)); + svCreate.save_data_size = create->nacp.user_account_save_data_size; + svCreate.journal_size = create->nacp.user_account_save_data_journal_size; + svCreate.available_size = create->nacp.user_account_save_data_size; + 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))) + { + ui::showPopup(POP_FRAME_DEFAULT, ui::saveCreated.c_str(), create->title.c_str()); + data::loadUsersTitles(false); + ui::setupTiles(NULL); + } + else + { + ui::showPopup(POP_FRAME_DEFAULT, ui::saveCreateFailed.c_str()); + } +} + +void ui::usrInit() +{ + usrMenu = new ui::menu; + usrOptMenu = new ui::menu; + saveCreateMenu = new ui::menu; + + usrMenu->setParams(64, 16, 0, 96, 4); + usrOptMenu->setParams(8, 32, 390, 18, 8); + usrOptMenu->setCallback(usrOptCallback, NULL); + + saveCreateMenu->setParams(8, 32, 390, 18, 8); + saveCreateMenu->setCallback(saveCreateCallback, NULL); + + for(data::user u : data::users) + { + usrMenu->addOpt(u.getUserIcon(), u.getUsername()); + unsigned ind = usrMenu->getOptPos(u.getUsername()); + usrMenu->setOptFunc(ind, FUNC_A, toTTL, NULL); + } + + usrMenu->addOpt(NULL, "Settings"); + optsPos = usrMenu->getOptPos("Settings"); + usrMenu->setOptFunc(optsPos, FUNC_A, toOPT, NULL); + + usrMenu->addOpt(NULL, "Extras"); + extPos = usrMenu->getOptPos("Extras"); + usrMenu->setOptFunc(extPos, FUNC_A, toEXT, NULL); + + usrMenu->setOnChangeFunc(onMainChange); + + usrMenu->editParam(MENU_RECT_WIDTH, 126); + + usrOptPanel = new ui::slideOutPanel(410, 720, 0, usrOptPanelDraw); + ui::addPanel(usrOptPanel); + usrOptMenu->addOpt(NULL, ui::usrOptString[0]); + usrOptMenu->setOptFunc(0, FUNC_A, usrOptSaveCreate, NULL); + usrOptMenu->setActive(false); + + saveCreatePanel = new ui::slideOutPanel(410, 720, 0, saveCreatePanelDraw); + saveCreateMenu->setActive(false); + ui::addPanel(saveCreatePanel); + unsigned i = 0; + for(auto& t : data::titles) + { + saveCreateMenu->addOpt(NULL, t.second.title); + saveCreateMenu->setOptFunc(i++, FUNC_A, createSaveData, saveCreateMenu); + sids.push_back(t.first); + } + + setupTiles(NULL); + + usrHelpX = 1220 - gfx::getTextWidth(ui::userHelp.c_str(), 18); +} + +void ui::usrExit() +{ + delete usrOptPanel; + delete saveCreatePanel; + delete usrMenu; + delete usrOptMenu; + delete saveCreateMenu; +} + +void ui::usrMenuSetActive(bool _set) +{ + usrMenu->setActive(_set); +} + +void ui::usrUpdate() +{ + usrMenu->update(); + usrOptMenu->update(); + saveCreateMenu->update(); + + if(!usrOptMenu->getActive() && !saveCreateMenu->getActive()) + { + switch(ui::padKeysDown()) + { + case HidNpadButton_X: + usrOptMenu->setActive(true); + usrMenu->setActive(false); + usrOptPanel->openPanel(); + break; + } + } +} + +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()); +} diff --git a/src/ui/usrsel.cpp b/src/ui/usrsel.cpp deleted file mode 100644 index 25e6f67..0000000 --- a/src/ui/usrsel.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include -#include -#include - -#include "data.h" -#include "ui.h" -#include "uiupdate.h" -#include "file.h" -#include "util.h" - -void ui::drawUserMenu() -{ - //Static so they don't get reset every loop - static int start = 0; - - static uint8_t clrShft = 0; - static bool clrAdd = true; - - static unsigned selRectX = 276, selRectY = 160; - - if(clrAdd) - { - clrShft += 6; - if(clrShft >= 0x72) - clrAdd = false; - } - else - { - clrShft -= 3; - if(clrShft <= 0) - clrAdd = true; - } - - unsigned x = 280, y = 164; - unsigned endUser = data::users.size(); - - drawBoundBox(selRectX, selRectY, 140, 140, clrShft); - - for(unsigned i = start; i < endUser; y += 136) - { - unsigned endRow = i + 5; - for(unsigned tX = x; i < endRow; i++, tX += 144) - { - if(i == endUser) - break; - - if((int)i == data::selUser) - { - selRectX = tX - 6; - selRectY = y - 6; - - unsigned userWidth = gfx::getTextWidth(data::curUser.getUsername().c_str(), 18); - int userRectWidth = userWidth + 32, userRectX = (tX + 64) - (userRectWidth / 2); - if(userRectX < 16) - userRectX = 16; - else if(userRectX + userRectWidth > 1264) - userRectX = 1264 - userRectWidth; - - drawTextbox(userRectX, y - 50, userRectWidth, 38); - gfx::drawTextf(18, userRectX + 16, y - 40, &ui::txtDiag, data::curUser.getUsername().c_str()); - } - data::users[i].drawIconHalf(tX, y); - } - } -} - -void ui::updateUserMenu(const uint64_t& down, const uint64_t& held) -{ - switch(down) - { - case HidNpadButton_A: - if(data::curUser.titles.size() > 0) - ui::changeState(TTL_SEL); - else - ui::showPopup(POP_FRAME_DEFAULT, ui::noSavesFound.c_str(), data::curUser.getUsername().c_str()); - break; - - case HidNpadButton_X: - ui::textMode = true; - ui::changeState(TXT_USR); - break; - - case HidNpadButton_Y: - { - bool cont = true; - for(unsigned i = 0; i < data::users.size() - 2; i++) - { - if(cont) - cont = fs::dumpAllUserSaves(data::users[i]); - } - } - break; - - case HidNpadButton_R: - util::checkForUpdate(); - break; - - case HidNpadButton_ZR: - ui::changeState(EX_MNU); - break; - - case HidNpadButton_Minus: - ui::changeState(OPT_MNU); - break; - - case HidNpadButton_StickLUp: - case HidNpadButton_Up: - data::selUser - 5 < 0 ? data::selUser = 0 : data::selUser -= 5; - break; - - case HidNpadButton_StickLDown: - case HidNpadButton_Down: - data::selUser + 5 > (int)data::users.size() - 1 ? data::selUser = data::users.size() - 1 : data::selUser += 5; - break; - - case HidNpadButton_StickLLeft: - case HidNpadButton_Left: - if(data::selUser > 0) - --data::selUser; - break; - - case HidNpadButton_StickLRight: - case HidNpadButton_Right: - if(data::selUser < (int)data::users.size() - 1) - ++data::selUser; - break; - } -} diff --git a/src/util.cpp b/src/util.cpp index e45f5b1..e6df75c 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -4,10 +4,10 @@ #include #include +#include "file.h" #include "data.h" #include "gfx.h" #include "util.h" -#include "file.h" #include "ui.h" #include "curlfuncs.h" @@ -133,17 +133,15 @@ std::string util::getDateTime(int fmt) void util::copyDirListToMenu(const fs::dirList& d, ui::menu& m) { m.reset(); - m.addOpt("."); - m.addOpt(".."); + m.addOpt(NULL, "."); + m.addOpt(NULL, ".."); for(unsigned i = 0; i < d.getCount(); i++) { if(d.isDir(i)) - m.addOpt("D " + d.getItem(i)); + m.addOpt(NULL, "D " + d.getItem(i)); else - m.addOpt("F " + d.getItem(i)); + m.addOpt(NULL, "F " + d.getItem(i)); } - - m.adjust(); } void util::removeLastFolderFromString(std::string& _path) @@ -173,7 +171,7 @@ std::string util::safeString(const std::string& s) } //Check for spaces at end - while(ret[ret.length() - 1] == ' ' || ret[ret.length() - 1] == '.') + while(ret[ret.length() - 1] == ' ') ret.erase(ret.length() - 1, 1); return ret; @@ -186,21 +184,25 @@ static inline std::string getTimeString(const uint32_t& _h, const uint32_t& _m) return std::string(tmp); } -std::string util::getInfoString(const data::user& u, const data::titledata& d) +std::string util::getInfoString(data::user& u, const uint64_t& tid) { - std::string ret = d.getTitle() + "\n"; + data::titleInfo *tinfo = data::getTitleInfoByTID(tid); + data::userTitleInfo *userTinfo = &u.titleInfo[data::selData]; - ret += "TID: " + d.getTIDStr() + "\n"; - ret += "SID: " + d.getSaveIDStr() + "\n"; + std::string ret = tinfo->title + "\n"; + + ret += "TID: " + util::getIDStr(tid) + "\n"; + ret += "SID: " + util::getIDStr(userTinfo->saveInfo.save_data_id) + "\n"; uint32_t hours, mins; - hours = d.getPlayTime() / 60; - mins = d.getPlayTime() - (hours * 60); + hours = userTinfo->playStats.playtimeMinutes / 60; + mins = userTinfo->playStats.playtimeMinutes - (hours * 60); ret += "Play Time: " + getTimeString(hours, mins) + "\n"; - ret += "Total Launches: " + std::to_string(d.getLaunchCount()) + "\n"; + ret += "Total Launches: " + std::to_string(userTinfo->playStats.totalLaunches) + "\n"; - switch(d.getType()) + + switch(userTinfo->saveInfo.save_data_type) { case FsSaveDataType_System: ret += "System Save\n"; @@ -267,13 +269,14 @@ std::string util::getStringInput(const std::string& def, const std::string& head return std::string(out); } -std::string util::generateAbbrev(const data::titledata& dat) +std::string util::generateAbbrev(const uint64_t& tid) { - size_t titleLength = dat.getTitle().length(); + data::titleInfo *tmp = data::getTitleInfoByTID(tid); + size_t titleLength = tmp->safeTitle.length(); char temp[titleLength + 1]; memset(temp, 0, titleLength + 1); - memcpy(temp, dat.getTitle().c_str(), titleLength); + memcpy(temp, tmp->safeTitle.c_str(), titleLength); std::string ret; char *tok = strtok(temp, " "); @@ -322,7 +325,7 @@ SDL_Texture *util::createIconGeneric(const char *txt, int fontSize) SDL_RenderClear(gfx::render); unsigned int x = 128 - (gfx::getTextWidth(txt, fontSize) / 2); unsigned int y = 128 - (fontSize / 2); - gfx::drawTextf(fontSize, x, y, &ui::txtCont, txt); + gfx::drawTextf(ret, fontSize, x, y, &ui::txtCont, txt); SDL_SetRenderTarget(gfx::render, NULL); return ret; } @@ -375,3 +378,14 @@ void util::checkForUpdate() json_object_put(jobj); } + +Result util::accountDeleteUser(AccountUid *uid) +{ + Service *account = accountGetServiceSession(); + struct + { + AccountUid uid; + } in = {*uid}; + + return serviceDispatchIn(account, 203, in); +}